From 76fae9bbaec043610e252b4adebb66d9870ad054 Mon Sep 17 00:00:00 2001 From: Anton Sviridov Date: Fri, 29 Nov 2024 09:02:15 +0000 Subject: [PATCH 1/9] WIP: cue4s port --- .scalafmt.conf | 2 +- build.sbt | 6 +- project/build.properties | 2 +- project/plugins.sbt | 2 +- src/main/scala/dex/main.scala | 48 +++++------ src/main/scala/dex/prompts.scala | 139 ++++++++++--------------------- 6 files changed, 76 insertions(+), 123 deletions(-) diff --git a/.scalafmt.conf b/.scalafmt.conf index cd041b1..ee905df 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,4 +1,4 @@ -version = "3.5.9" +version = "3.8.3" runner.dialect = scala3 fileOverride { "glob:**/scaladex/src/**" { diff --git a/build.sbt b/build.sbt index 2318510..6eaca68 100644 --- a/build.sbt +++ b/build.sbt @@ -5,10 +5,11 @@ enablePlugins(NpmPackagePlugin) name := "dexsearch" version := "0.1.5" -scalaVersion := "3.2.1" // or any other Scala version >= 2.11.12 +scalaVersion := "3.3.4" // or any other Scala version >= 2.11.12 libraryDependencies ++= Seq( - "com.monovore" %%% "decline-effect" % "2.4.1" + "com.monovore" %%% "decline-effect" % "2.4.1", + "tech.neander" %%% "cue4s-cats-effect" % "dev" ) // This is an application with a main method @@ -27,7 +28,6 @@ npmPackageBinaryEnable := true npmPackageDependencies ++= { Seq( "node-fetch" -> "^2.6.1", - "prompts" -> "^2.4.2", "clipboardy" -> "^3.0.0" ) } diff --git a/project/build.properties b/project/build.properties index 46e43a9..db1723b 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.8.2 +sbt.version=1.10.5 diff --git a/project/plugins.sbt b/project/plugins.sbt index 2764f09..26fd547 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,3 +1,3 @@ // addSbtPlugin("org.scalablytyped.converter" % "sbt-converter" % "1.0.0-beta40") -addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.12.0") +addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.17.0") addSbtPlugin("io.chrisdavenport" % "sbt-npm-package" % "0.1.2") diff --git a/src/main/scala/dex/main.scala b/src/main/scala/dex/main.scala index d1f97a1..5e0b30a 100644 --- a/src/main/scala/dex/main.scala +++ b/src/main/scala/dex/main.scala @@ -3,9 +3,6 @@ package dex import scala.scalajs.js import scala.scalajs.js.annotation.JSImport -// @main -def main() = println(util.inspect(prompts.default)) - import scala.scalajs.js import scala.scalajs.js.JSConverters._ import scala.util.Success @@ -16,6 +13,7 @@ import cats.syntax.all._ import com.monovore.decline.effect.CommandIOApp import cats.effect.IO import cats.effect.ExitCode +import cue4s.catseffect.PromptsIO object Main extends CommandIOApp("dex", "searches scaladex for Scala libraries"): @@ -24,18 +22,20 @@ object Main def main = (BuildTool.opt, LibName.argument).mapN { (maybeBuildTool, maybeLibName) => - for - libName <- maybeLibName.map(IO.pure(_)).getOrElse(promptLibName) - projects <- scaladex.search(libName.value) - project <- promptProject(projects) - modules <- promptModules(project) - details <- scaladex.project(project.organization, project.repository) - version <- promptVersion(details) - buildTool <- maybeBuildTool.map(IO.pure(_)).getOrElse(promptBuildTool) - content = format(buildTool, details.groupId, modules, version) - _ <- copyToClipboard(content) - _ <- IO.println(doneMessage) - yield ExitCode(0) + PromptsIO().use: + prompts => + for + libName <- maybeLibName.map(IO.pure(_)).getOrElse(promptLibName(prompts)) + projects <- scaladex.search(libName.value) + project <- promptProject(prompts, projects) + modules <- promptModules(prompts, project) + details <- scaladex.project(project.organization, project.repository) + version <- promptVersion(prompts, details) + buildTool <- maybeBuildTool.map(IO.pure(_)).getOrElse(promptBuildTool(prompts)) + content = format(buildTool, details.groupId, modules, version) + _ <- copyToClipboard(content) + _ <- IO.println(doneMessage) + yield ExitCode(0) } end main @@ -45,14 +45,14 @@ object Main modules: js.Array[String], version: String ): List[String] = modules.toList.map { case module => - buildTool match - case BuildTool.SBT => s""""$groupId" %% "$module" % "$version"""" - case BuildTool.Mill => s"""ivy"$groupId::$module:$version"""" - case BuildTool.Bleep => s"""$groupId::$module:$version""" - case BuildTool.ScalaCLI => - s"""//> using lib "$groupId::$module:$version"""" - case BuildTool.Ammonite => - s"""import $$ivy.`$groupId::$module:$version`""" - } + buildTool match + case BuildTool.SBT => s""""$groupId" %% "$module" % "$version"""" + case BuildTool.Mill => s"""ivy"$groupId::$module:$version"""" + case BuildTool.Bleep => s"""$groupId::$module:$version""" + case BuildTool.ScalaCLI => + s"""//> using lib "$groupId::$module:$version"""" + case BuildTool.Ammonite => + s"""import $$ivy.`$groupId::$module:$version`""" + } end Main diff --git a/src/main/scala/dex/prompts.scala b/src/main/scala/dex/prompts.scala index ef3ce0d..3149171 100644 --- a/src/main/scala/dex/prompts.scala +++ b/src/main/scala/dex/prompts.scala @@ -6,104 +6,57 @@ import scala.scalajs.js.Promise import scala.scalajs.js.Thenable import cats.effect.IO import scala.scalajs.js.JSConverters._ - -@js.native -@JSImport("prompts", JSImport.Namespace) -object prompts extends js.Any: - def default[T](x: js.Object): Promise[T] = js.native - -def ioPrompt[T](x: js.Object): IO[T] = - IO.fromPromise(IO(prompts.default(x))) - -def promptLibName: IO[LibName] = - val libNameQuestion = new js.Object { - val `type` = "text" - val name = "libName" - val message = "Which library ?" - } - - trait LibNameAnswer extends js.Object { - val libName: String - } - - ioPrompt[LibNameAnswer](libNameQuestion).map(_.libName).map(LibName(_)) -end promptLibName - -def promptProject(project: js.Array[Project]): IO[Project] = - val projectQuestion = new js.Object { - val `type` = "autocomplete" - val name = "project" - val message = "From which repo ?" - val choices = project.map { p => - new js.Object { - val title = s"${p.repository} from ${p.organization}" - val value = p - } - } - } - - trait ProjectAnswer extends js.Object { - val project: Project - } - - ioPrompt[ProjectAnswer](projectQuestion).map(_.project) +import cue4s.*, catseffect.PromptsIO + +def promptLibName(prompts: PromptsIO): IO[LibName] = + prompts + .io(Prompt.Input("Which library?")) + .map(_.toEither) + .flatMap(IO.fromEither) + .map(LibName(_)) + +def promptProject(prompts: PromptsIO, project: js.Array[Project]): IO[Project] = + val mapping = project.toList + .map: p => + val title = s"${p.repository} from ${p.organization}" + val value = p + + title -> p + .toMap + + prompts + .io(Prompt.SingleChoice("From which repo?", mapping.keySet.toList.sorted)) + .map(_.toEither) + .flatMap(IO.fromEither) + .map(mapping(_)) end promptProject -def promptModules(project: Project): IO[js.Array[String]] = - val moduleQuestion = new js.Object { - val `type` = "autocompleteMultiselect" - val name = "modules" - val message = "Which modules ?" - val choices = project.artifacts.map { artifact => - new js.Object { - val title = artifact - val value = artifact - } - } - } - - trait ProjectAnswer extends js.Object { - val modules: js.Array[String] - } +def promptModules(prompts: PromptsIO, project: Project): IO[js.Array[String]] = + val choices = project.artifacts.toList - ioPrompt[ProjectAnswer](moduleQuestion).map(_.modules) + prompts + .io(Prompt.MultipleChoice.withNoneSelected("Which modules?", choices)) + .map(_.toEither) + .flatMap(IO.fromEither) + .map(_.toJSArray) end promptModules -def promptVersion(project: ProjectDetails): IO[String] = - val versionQuestion = new js.Object { - val `type` = "autocomplete" - val name = "version" - val message = "Which version ?" - val choices = project.versions.map { version => - new js.Object { - val title = version - val value = version - } - } - } - - trait VersionAnswer extends js.Object: - val version: String - - ioPrompt[VersionAnswer](versionQuestion).map(_.version) +def promptVersion(prompts: PromptsIO, project: ProjectDetails): IO[String] = + prompts + .io(Prompt.SingleChoice("Which version?", project.versions.toList)) + .map(_.toEither) + .flatMap(IO.fromEither) end promptVersion -def promptBuildTool: IO[BuildTool] = - val versionQuestion = new js.Object { - val `type` = "select" - val name = "buildTool" - val message = "Which build tool ?" - val choices = BuildTool.values.map { bt => - new js.Object { - val title = bt.toString() - val value = bt - } - }.toJSArray - } - - trait VersionAnswer extends js.Object { - val buildTool: BuildTool - } - - ioPrompt[VersionAnswer](versionQuestion).map(_.buildTool) +def promptBuildTool(prompts: PromptsIO): IO[BuildTool] = + prompts + .io( + Prompt.SingleChoice( + "Which build tool?", + BuildTool.values.map(_.toString).toList + ) + ) + .map(_.toEither) + .flatMap(IO.fromEither) + .map(BuildTool.valueOf) end promptBuildTool From cdd32c448d836a05cb6217c8358df7a8c4847bcc Mon Sep 17 00:00:00 2001 From: Anton Sviridov Date: Fri, 29 Nov 2024 10:03:34 +0000 Subject: [PATCH 2/9] Error handling --- src/main/scala/dex/main.scala | 22 +++++++++++++++++----- src/main/scala/dex/prompts.scala | 12 +++++++----- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/main/scala/dex/main.scala b/src/main/scala/dex/main.scala index 5e0b30a..9c143a2 100644 --- a/src/main/scala/dex/main.scala +++ b/src/main/scala/dex/main.scala @@ -14,6 +14,7 @@ import com.monovore.decline.effect.CommandIOApp import cats.effect.IO import cats.effect.ExitCode import cue4s.catseffect.PromptsIO +import cue4s.CompletionError object Main extends CommandIOApp("dex", "searches scaladex for Scala libraries"): @@ -22,20 +23,31 @@ object Main def main = (BuildTool.opt, LibName.argument).mapN { (maybeBuildTool, maybeLibName) => - PromptsIO().use: - prompts => + PromptsIO() + .use: prompts => for - libName <- maybeLibName.map(IO.pure(_)).getOrElse(promptLibName(prompts)) + libName <- maybeLibName + .map(IO.pure(_)) + .getOrElse(promptLibName(prompts)) projects <- scaladex.search(libName.value) project <- promptProject(prompts, projects) modules <- promptModules(prompts, project) - details <- scaladex.project(project.organization, project.repository) + details <- scaladex.project( + project.organization, + project.repository + ) version <- promptVersion(prompts, details) - buildTool <- maybeBuildTool.map(IO.pure(_)).getOrElse(promptBuildTool(prompts)) + buildTool <- maybeBuildTool + .map(IO.pure(_)) + .getOrElse(promptBuildTool(prompts)) content = format(buildTool, details.groupId, modules, version) _ <- copyToClipboard(content) _ <- IO.println(doneMessage) yield ExitCode(0) + .recoverWith: + case CompletionError.Interrupted => + IO.println("cancelled").as(ExitCode.Error) + case CompletionError.Error(msg) => IO.println(msg).as(ExitCode.Error) } end main diff --git a/src/main/scala/dex/prompts.scala b/src/main/scala/dex/prompts.scala index 3149171..d237c6e 100644 --- a/src/main/scala/dex/prompts.scala +++ b/src/main/scala/dex/prompts.scala @@ -24,11 +24,13 @@ def promptProject(prompts: PromptsIO, project: js.Array[Project]): IO[Project] = title -> p .toMap - prompts - .io(Prompt.SingleChoice("From which repo?", mapping.keySet.toList.sorted)) - .map(_.toEither) - .flatMap(IO.fromEither) - .map(mapping(_)) + if mapping.isEmpty then IO.raiseError(CompletionError.Error("no repos found")) + else + prompts + .io(Prompt.SingleChoice("From which repo?", mapping.keySet.toList.sorted)) + .map(_.toEither) + .flatMap(IO.fromEither) + .map(mapping(_)) end promptProject def promptModules(prompts: PromptsIO, project: Project): IO[js.Array[String]] = From 9fe96b71a5f5e8340eb0ede02b200d35d363bdb5 Mon Sep 17 00:00:00 2001 From: Anton Sviridov Date: Sat, 30 Nov 2024 20:19:56 +0000 Subject: [PATCH 3/9] Update to stable cue4s 0.0.3 --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 6eaca68..7c5ae62 100644 --- a/build.sbt +++ b/build.sbt @@ -9,7 +9,7 @@ scalaVersion := "3.3.4" // or any other Scala version >= 2.11.12 libraryDependencies ++= Seq( "com.monovore" %%% "decline-effect" % "2.4.1", - "tech.neander" %%% "cue4s-cats-effect" % "dev" + "tech.neander" %%% "cue4s-cats-effect" % "0.0.3" ) // This is an application with a main method From dd1d8c62a75e38976219c9a9226f4974a5380781 Mon Sep 17 00:00:00 2001 From: Anton Sviridov Date: Fri, 6 Dec 2024 12:52:46 +0000 Subject: [PATCH 4/9] Update to 0.0.6 --- build.sbt | 2 +- src/main/scala/dex/main.scala | 2 +- src/main/scala/dex/prompts.scala | 16 +++++++--------- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/build.sbt b/build.sbt index 7c5ae62..40056ec 100644 --- a/build.sbt +++ b/build.sbt @@ -9,7 +9,7 @@ scalaVersion := "3.3.4" // or any other Scala version >= 2.11.12 libraryDependencies ++= Seq( "com.monovore" %%% "decline-effect" % "2.4.1", - "tech.neander" %%% "cue4s-cats-effect" % "0.0.3" + "tech.neander" %%% "cue4s-cats-effect" % "0.0.6" ) // This is an application with a main method diff --git a/src/main/scala/dex/main.scala b/src/main/scala/dex/main.scala index 9c143a2..e363ba6 100644 --- a/src/main/scala/dex/main.scala +++ b/src/main/scala/dex/main.scala @@ -23,7 +23,7 @@ object Main def main = (BuildTool.opt, LibName.argument).mapN { (maybeBuildTool, maybeLibName) => - PromptsIO() + PromptsIO.make .use: prompts => for libName <- maybeLibName diff --git a/src/main/scala/dex/prompts.scala b/src/main/scala/dex/prompts.scala index d237c6e..89b5952 100644 --- a/src/main/scala/dex/prompts.scala +++ b/src/main/scala/dex/prompts.scala @@ -10,7 +10,7 @@ import cue4s.*, catseffect.PromptsIO def promptLibName(prompts: PromptsIO): IO[LibName] = prompts - .io(Prompt.Input("Which library?")) + .text("Which library?") .map(_.toEither) .flatMap(IO.fromEither) .map(LibName(_)) @@ -27,7 +27,7 @@ def promptProject(prompts: PromptsIO, project: js.Array[Project]): IO[Project] = if mapping.isEmpty then IO.raiseError(CompletionError.Error("no repos found")) else prompts - .io(Prompt.SingleChoice("From which repo?", mapping.keySet.toList.sorted)) + .singleChoice("From which repo?", mapping.keySet.toList.sorted) .map(_.toEither) .flatMap(IO.fromEither) .map(mapping(_)) @@ -37,7 +37,7 @@ def promptModules(prompts: PromptsIO, project: Project): IO[js.Array[String]] = val choices = project.artifacts.toList prompts - .io(Prompt.MultipleChoice.withNoneSelected("Which modules?", choices)) + .multiChoiceNoneSelected("Which modules?", choices) .map(_.toEither) .flatMap(IO.fromEither) .map(_.toJSArray) @@ -45,18 +45,16 @@ end promptModules def promptVersion(prompts: PromptsIO, project: ProjectDetails): IO[String] = prompts - .io(Prompt.SingleChoice("Which version?", project.versions.toList)) + .singleChoice("Which version?", project.versions.toList) .map(_.toEither) .flatMap(IO.fromEither) end promptVersion def promptBuildTool(prompts: PromptsIO): IO[BuildTool] = prompts - .io( - Prompt.SingleChoice( - "Which build tool?", - BuildTool.values.map(_.toString).toList - ) + .singleChoice( + "Which build tool?", + BuildTool.values.map(_.toString).toList ) .map(_.toEither) .flatMap(IO.fromEither) From 526c8ed1ba33c090c6aec0c369e10b7d271ad4d2 Mon Sep 17 00:00:00 2001 From: Anton Sviridov Date: Wed, 24 Jun 2026 13:46:15 +0100 Subject: [PATCH 5/9] Native implementation --- .github/workflows/native.yml | 180 +++++ .scalafmt.conf | 2 +- build.sbt | 73 +- cli/src/main/scala/dex/Clipboard.scala | 8 + {src => cli/src}/main/scala/dex/LibName.scala | 0 cli/src/main/scala/dex/Scaladex.scala | 26 + .../src}/main/scala/dex/buildTool.scala | 0 {src => cli/src}/main/scala/dex/main.scala | 16 +- {src => cli/src}/main/scala/dex/prompts.scala | 11 +- cli/src/main/scalajs/ScaladexPlatform.scala | 66 ++ cli/src/main/scalajs/clipboard.scala | 21 + .../dex => cli/src/main/scalajs}/fetch.scala | 0 .../main/scalanative/ClipboardPlatform.scala | 59 ++ .../main/scalanative/ScaladexPlatform.scala | 34 + package-lock.json | 714 +++++++++++++++--- package.json | 5 +- project/build.properties | 2 +- project/plugins.sbt | 5 +- src/main/scala/dex/clipboard.scala | 20 - src/main/scala/dex/scaladex.scala | 51 -- src/main/scala/dex/util.scala | 12 - 21 files changed, 1051 insertions(+), 254 deletions(-) create mode 100644 .github/workflows/native.yml create mode 100644 cli/src/main/scala/dex/Clipboard.scala rename {src => cli/src}/main/scala/dex/LibName.scala (100%) create mode 100644 cli/src/main/scala/dex/Scaladex.scala rename {src => cli/src}/main/scala/dex/buildTool.scala (100%) rename {src => cli/src}/main/scala/dex/main.scala (84%) rename {src => cli/src}/main/scala/dex/prompts.scala (78%) create mode 100644 cli/src/main/scalajs/ScaladexPlatform.scala create mode 100644 cli/src/main/scalajs/clipboard.scala rename {src/main/scala/dex => cli/src/main/scalajs}/fetch.scala (100%) create mode 100644 cli/src/main/scalanative/ClipboardPlatform.scala create mode 100644 cli/src/main/scalanative/ScaladexPlatform.scala delete mode 100644 src/main/scala/dex/clipboard.scala delete mode 100644 src/main/scala/dex/scaladex.scala delete mode 100644 src/main/scala/dex/util.scala diff --git a/.github/workflows/native.yml b/.github/workflows/native.yml new file mode 100644 index 0000000..1873af7 --- /dev/null +++ b/.github/workflows/native.yml @@ -0,0 +1,180 @@ +name: Native +on: + push: + branches: ["main"] + tags: ["v*"] + pull_request: + branches: ["*"] + +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: true + +jobs: + macos_build: + name: MacOS (${{ matrix.OS }}) + strategy: + fail-fast: true + matrix: + OS: ["macos-15", "macos-15-intel"] + runs-on: ${{ matrix.OS }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup + uses: actions/setup-java@v4 + with: + java-version: 21 + distribution: temurin + + - uses: sbt/setup-sbt@v1 + + - uses: coursier/cache-action@v6 + + - name: Build the binary + run: | + sbt buildBinaryPlatformRelease + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + path: out/release/* + name: ${{ matrix.os }}-binaries + if-no-files-found: error + + linux_build: + name: Linux (${{ matrix.OS }}) + strategy: + fail-fast: true + matrix: + OS: ["ubuntu-22.04", "ubuntu-22.04-arm"] + runs-on: ${{ matrix.OS }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: actions/setup-java@v4 + with: + distribution: "temurin" + java-version: "21" + + - uses: sbt/setup-sbt@v1 + + - uses: coursier/cache-action@v6 + + - name: Build the binary + run: | + sbt buildBinaryPlatformRelease + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + path: out/release/* + name: ${{ matrix.os }}-binaries + if-no-files-found: error + + windows_build: + name: Windows + strategy: + fail-fast: false + runs-on: windows-2022 + env: + LLVM_BIN: 'C:\Program Files\LLVM\bin' + LLVM_VERSION: "20.1.0" + steps: + # This step is important to make sure scalafmt + # checks don't fail + - name: Setup git config + run: git config --global core.autocrlf false + + - uses: actions/checkout@v4 + + - uses: actions/setup-java@v4 + with: + distribution: "temurin" + java-version: "21" + + - uses: coursier/cache-action@v6 + + - uses: sbt/setup-sbt@v1 + + - name: Cache SBT + uses: actions/cache@v5 + with: + path: | + %LocalAppData%\sbt\v2 + key: ${{ runner.os }}-sbt2 + + - name: Build the binary + run: | + sbt buildBinaryPlatformRelease + + # - name: Upload artifacts + # uses: actions/upload-artifact@v4 + # with: + # path: out/release/* + # name: windows-binaries + # if-no-files-found: error + # + publish: + if: startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main' + needs: [linux_build] + name: Publish to Maven Central + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup + uses: actions/setup-java@v4 + with: + java-version: 21 + distribution: temurin + + - uses: sbt/setup-sbt@v1 + + - uses: coursier/cache-action@v6 + + - name: Publish to Maven + run: sbt ci-release + env: + PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }} + PGP_SECRET: ${{ secrets.PGP_SECRET }} + SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} + SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} + + release: + if: startsWith(github.ref, 'refs/tags/v') + needs: [linux_build, windows_build, macos_build] + name: Upload binaries to release + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Download binaries + uses: actions/download-artifact@v4 + id: download + with: + path: binaries + + - name: List downloaded binaries + run: ls -R binaries + + - name: Upload release binaries + uses: softprops/action-gh-release@v2 + if: startsWith(github.ref, 'refs/tags/') + with: + files: "${{steps.download.outputs.download-path}}/**/*" + + mergify-build-checkpoint: + runs-on: ubuntu-latest + needs: [linux_build, windows_build, macos_build] + steps: + - name: I only exist to please Mergify :( + run: echo "It's a sad existence but necessary" diff --git a/.scalafmt.conf b/.scalafmt.conf index ee905df..306538f 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,4 +1,4 @@ -version = "3.8.3" +version = "3.10.6" runner.dialect = scala3 fileOverride { "glob:**/scaladex/src/**" { diff --git a/build.sbt b/build.sbt index 40056ec..9bf5a4b 100644 --- a/build.sbt +++ b/build.sbt @@ -2,32 +2,55 @@ import org.scalajs.linker.interface.StandardConfig enablePlugins(ScalaJSPlugin) enablePlugins(NpmPackagePlugin) -name := "dexsearch" -version := "0.1.5" +// name := "dexsearch" +// version := "0.1.5" -scalaVersion := "3.3.4" // or any other Scala version >= 2.11.12 - -libraryDependencies ++= Seq( - "com.monovore" %%% "decline-effect" % "2.4.1", - "tech.neander" %%% "cue4s-cats-effect" % "0.0.6" -) - -// This is an application with a main method -scalaJSUseMainModuleInitializer := true -Compile / scalaJSLinkerConfig := { - val c = scalaJSLinkerConfig.value - c.withModuleKind(ModuleKind.ESModule).withJSHeader("#!/usr/bin/env node\n") +lazy val Versions = new { + val Scala = "3.9.0-RC1" } -licenses := Seq(License.Apache2) -npmPackageAuthor := "Neandertech" -npmPackageDescription := "CLI that uses the Scaladex API to quickly search libraries and copy them to the clipboard" -npmPackageName := "dexsearch" -npmPackageNpmrcScope := Some("neandertech") -npmPackageBinaryEnable := true -npmPackageDependencies ++= { - Seq( - "node-fetch" -> "^2.6.1", - "clipboardy" -> "^3.0.0" +lazy val root = project.in(file(".")).aggregate(dexsearch.projectRefs *) + +lazy val dexsearch = projectMatrix + .in(file("cli")) + .nativePlatform( + Seq(Versions.Scala), + Seq.empty, + _.enablePlugins(ForgeNativeBinaryPlugin).settings( + Seq( + libraryDependencies += "com.softwaremill.sttp.client4" %%% "core" % "4.0.25", + libraryDependencies += "com.softwaremill.sttp.client4" %%% "upickle" % "4.0.25" + ) + ) ) -} + .jsPlatform( + Seq(Versions.Scala), + Seq.empty, + _.enablePlugins(ScalaJSPlugin, NpmPackagePlugin).settings( + scalaJSUseMainModuleInitializer := true, + Compile / scalaJSLinkerConfig := { + val c = scalaJSLinkerConfig.value + c.withModuleKind(ModuleKind.ESModule) + .withJSHeader("#!/usr/bin/env node\n") + }, + npmPackageAuthor := "Neandertech", + npmPackageDescription := "CLI that uses the Scaladex API to quickly search libraries and copy them to the clipboard", + npmPackageName := "dexsearch", + npmPackageNpmrcScope := Some("neandertech"), + npmPackageBinaryEnable := true, + npmPackageDependencies ++= { + Seq( + "node-fetch" -> "3.3.2", + "clipboardy" -> "5.3.1" + ) + } + ) + ) + .settings( + libraryDependencies ++= Seq( + "com.monovore" %%% "decline-effect" % "2.6.2", + "tech.neander" %%% "cue4s-cats-effect" % "dev" + ) + ) + +inThisBuild(List(licenses := Seq(License.Apache2))) diff --git a/cli/src/main/scala/dex/Clipboard.scala b/cli/src/main/scala/dex/Clipboard.scala new file mode 100644 index 0000000..4ac6738 --- /dev/null +++ b/cli/src/main/scala/dex/Clipboard.scala @@ -0,0 +1,8 @@ +package dex + +import cats.effect.IO + +trait Clipboard: + def copyToClipboard(lines: Seq[String]): IO[Unit] + +object Clipboard extends ClipboardPlatform diff --git a/src/main/scala/dex/LibName.scala b/cli/src/main/scala/dex/LibName.scala similarity index 100% rename from src/main/scala/dex/LibName.scala rename to cli/src/main/scala/dex/LibName.scala diff --git a/cli/src/main/scala/dex/Scaladex.scala b/cli/src/main/scala/dex/Scaladex.scala new file mode 100644 index 0000000..c4aa750 --- /dev/null +++ b/cli/src/main/scala/dex/Scaladex.scala @@ -0,0 +1,26 @@ +package dex + +import cats.effect.IO + +trait Scaladex: + protected val target = "JVM" + protected val scalaVersion = "2.13" + + def search(name: String): IO[Array[Project]] + def project(org: String, repo: String): IO[ProjectDetails] + +object Scaladex extends ScaladexPlatform + + +case class Project( + organization: String, + repository: String, + artifacts: Array[String] +) + +case class ProjectDetails( + groupId: String, + version: String, + artifacts: Array[String], + versions: Array[String] +) diff --git a/src/main/scala/dex/buildTool.scala b/cli/src/main/scala/dex/buildTool.scala similarity index 100% rename from src/main/scala/dex/buildTool.scala rename to cli/src/main/scala/dex/buildTool.scala diff --git a/src/main/scala/dex/main.scala b/cli/src/main/scala/dex/main.scala similarity index 84% rename from src/main/scala/dex/main.scala rename to cli/src/main/scala/dex/main.scala index e363ba6..78d80a1 100644 --- a/src/main/scala/dex/main.scala +++ b/cli/src/main/scala/dex/main.scala @@ -1,10 +1,5 @@ package dex -import scala.scalajs.js -import scala.scalajs.js.annotation.JSImport - -import scala.scalajs.js -import scala.scalajs.js.JSConverters._ import scala.util.Success import scala.util.Failure import com.monovore.decline.CommandApp @@ -23,16 +18,17 @@ object Main def main = (BuildTool.opt, LibName.argument).mapN { (maybeBuildTool, maybeLibName) => + Clipboard.copyToClipboard(Seq("hello", "poopoo")) *> PromptsIO.make .use: prompts => for libName <- maybeLibName .map(IO.pure(_)) .getOrElse(promptLibName(prompts)) - projects <- scaladex.search(libName.value) + projects <- Scaladex.search(libName.value) project <- promptProject(prompts, projects) modules <- promptModules(prompts, project) - details <- scaladex.project( + details <- Scaladex.project( project.organization, project.repository ) @@ -41,7 +37,7 @@ object Main .map(IO.pure(_)) .getOrElse(promptBuildTool(prompts)) content = format(buildTool, details.groupId, modules, version) - _ <- copyToClipboard(content) + _ <- Clipboard.copyToClipboard(content) _ <- IO.println(doneMessage) yield ExitCode(0) .recoverWith: @@ -54,7 +50,7 @@ object Main def format( buildTool: BuildTool, groupId: String, - modules: js.Array[String], + modules: Array[String], version: String ): List[String] = modules.toList.map { case module => buildTool match @@ -62,7 +58,7 @@ object Main case BuildTool.Mill => s"""ivy"$groupId::$module:$version"""" case BuildTool.Bleep => s"""$groupId::$module:$version""" case BuildTool.ScalaCLI => - s"""//> using lib "$groupId::$module:$version"""" + s"""//> using dep "$groupId::$module:$version"""" case BuildTool.Ammonite => s"""import $$ivy.`$groupId::$module:$version`""" } diff --git a/src/main/scala/dex/prompts.scala b/cli/src/main/scala/dex/prompts.scala similarity index 78% rename from src/main/scala/dex/prompts.scala rename to cli/src/main/scala/dex/prompts.scala index 89b5952..69e4341 100644 --- a/src/main/scala/dex/prompts.scala +++ b/cli/src/main/scala/dex/prompts.scala @@ -1,11 +1,6 @@ package dex -import scala.scalajs.js -import scala.scalajs.js.annotation.JSImport -import scala.scalajs.js.Promise -import scala.scalajs.js.Thenable import cats.effect.IO -import scala.scalajs.js.JSConverters._ import cue4s.*, catseffect.PromptsIO def promptLibName(prompts: PromptsIO): IO[LibName] = @@ -15,7 +10,7 @@ def promptLibName(prompts: PromptsIO): IO[LibName] = .flatMap(IO.fromEither) .map(LibName(_)) -def promptProject(prompts: PromptsIO, project: js.Array[Project]): IO[Project] = +def promptProject(prompts: PromptsIO, project: Array[Project]): IO[Project] = val mapping = project.toList .map: p => val title = s"${p.repository} from ${p.organization}" @@ -33,14 +28,14 @@ def promptProject(prompts: PromptsIO, project: js.Array[Project]): IO[Project] = .map(mapping(_)) end promptProject -def promptModules(prompts: PromptsIO, project: Project): IO[js.Array[String]] = +def promptModules(prompts: PromptsIO, project: Project): IO[Array[String]] = val choices = project.artifacts.toList prompts .multiChoiceNoneSelected("Which modules?", choices) .map(_.toEither) .flatMap(IO.fromEither) - .map(_.toJSArray) + .map(_.toArray) end promptModules def promptVersion(prompts: PromptsIO, project: ProjectDetails): IO[String] = diff --git a/cli/src/main/scalajs/ScaladexPlatform.scala b/cli/src/main/scalajs/ScaladexPlatform.scala new file mode 100644 index 0000000..ca64819 --- /dev/null +++ b/cli/src/main/scalajs/ScaladexPlatform.scala @@ -0,0 +1,66 @@ +package dex + +import scala.scalajs.js +import scala.scalajs.js.JSConverters._ +import scala.scalajs.js.Thenable +import cats.effect.IO + +trait ScaladexPlatform extends Scaladex: + + + def search(name: String): IO[Array[Project]] = + val n = name.trim() + ioFetch + .get( + s"https://index.scala-lang.org/api/search?q=$n&target=$target&scalaVersion=$scalaVersion" + ) + .flatMap(_.json) + .map { json => + json + .asInstanceOf[js.Array[ProjectJS]] + .filter { project => + project.repository.contains(n) || project.artifacts + .exists(_.contains(n)) + + } + .map { json => + Project( + organization = json.organization, + repository = json.repository, + artifacts = json.artifacts.toArray + ) + } + .toArray + } + + def project(org: String, repo: String): IO[ProjectDetails] = + ioFetch + .get( + s"https://index.scala-lang.org/api/project?organization=$org&repository=$repo" + ) + .flatMap(_.json) + .map { json => + json.asInstanceOf[ProjectDetailsJS] + } + .map { json => + ProjectDetails( + groupId = json.groupId, + version = json.version, + artifacts = json.artifacts.toArray, + versions = json.versions.toArray + ) + } + end project + +@js.native +trait ProjectJS extends js.Object: + def organization: String = js.native + def repository: String = js.native + def artifacts: js.Array[String] = js.native + +@js.native +trait ProjectDetailsJS extends js.Object: + def artifacts: js.Array[String] + def versions: js.Array[String] + def groupId: String + def version: String diff --git a/cli/src/main/scalajs/clipboard.scala b/cli/src/main/scalajs/clipboard.scala new file mode 100644 index 0000000..375fbca --- /dev/null +++ b/cli/src/main/scalajs/clipboard.scala @@ -0,0 +1,21 @@ +package dex + +import scala.scalajs.js +import scala.scalajs.js.annotation.JSImport +import cats.effect.IO + +@JSImport("clipboardy", JSImport.Namespace) +@js.native +private object clipboardy extends js.Object: + val default: ClipboardJS = js.native + +@js.native +private trait ClipboardJS extends js.Any: + def write(s: String): js.Promise[Unit] = js.native + +trait ClipboardPlatform extends Clipboard: + def copyToClipboard(lines: Seq[String]): IO[Unit] = IO.fromPromise { + IO { + clipboardy.default.write(lines.mkString(System.lineSeparator())) + } + } diff --git a/src/main/scala/dex/fetch.scala b/cli/src/main/scalajs/fetch.scala similarity index 100% rename from src/main/scala/dex/fetch.scala rename to cli/src/main/scalajs/fetch.scala diff --git a/cli/src/main/scalanative/ClipboardPlatform.scala b/cli/src/main/scalanative/ClipboardPlatform.scala new file mode 100644 index 0000000..90e4fea --- /dev/null +++ b/cli/src/main/scalanative/ClipboardPlatform.scala @@ -0,0 +1,59 @@ +package dex + +import cats.effect.IO +import cats.syntax.all.* + +import scalanative.meta.LinktimeInfo + +trait ClipboardPlatform extends Clipboard: + def copyToClipboard(lines: Seq[String]): IO[Unit] = + provider.copyToClipboard(lines) + +val provider = + if LinktimeInfo.isMac then MacosProvider + else if LinktimeInfo.isWindows then WindowsProvider + else if LinktimeInfo.isLinux then LinuxProvider + else Fallback + +object Fallback extends Clipboard: + override def copyToClipboard(lines: Seq[String]): IO[Unit] = + val console = cats.effect.std.Console[IO] + + import console.* + + for + _ <- errorln( + "Your system does not have any known clipboard managing tools" + ) + _ <- errorln("Here are the lines that would've been copied:") + _ <- lines.traverse(errorln(_)) + yield () + +object MacosProvider extends Clipboard: + override def copyToClipboard(lines: Seq[String]): IO[Unit] = IO( + pipe(lines, Seq("pbcopy")) + ) + +object LinuxProvider extends Clipboard: + override def copyToClipboard(lines: Seq[String]): IO[Unit] = + IO(pipe(lines, Seq("xsel", "--clipboard", "--input"))).recoverWith(_ => + IO(pipe(lines, Seq("wl-copy", "--type", "text/plain"))) + ) + +object WindowsProvider extends Clipboard: + override def copyToClipboard(lines: Seq[String]): IO[Unit] = + IO(pipe(lines, Seq("clip.exe"))) + +private def pipe(lines: Seq[String], process: Seq[String]) = + import java.lang.process.* + val p = ProcessBuilder.apply(process*) + val s = p.start() + val stream = s.getOutputStream() + stream.write(lines.mkString(System.lineSeparator()).getBytes()) + + stream.close() + + assert( + s.waitFor() == 0, + s"Process [${process.mkString(" ")}] exited with code ${s.exitValue()}" + ) diff --git a/cli/src/main/scalanative/ScaladexPlatform.scala b/cli/src/main/scalanative/ScaladexPlatform.scala new file mode 100644 index 0000000..4a8a65b --- /dev/null +++ b/cli/src/main/scalanative/ScaladexPlatform.scala @@ -0,0 +1,34 @@ +package dex + +import cats.effect.IO + +import sttp.client4.* +import sttp.client4.upicklejson.default.* +import upickle.default.* +import sttp.client4.curl.CurlTryBackend + +trait ScaladexPlatform extends Scaladex: + + given Reader[Project] = macroR + given Reader[ProjectDetails] = macroR + + def search(name: String): IO[Array[Project]] = + val n = name.trim + IO.fromTry( + basicRequest + .get( + uri"https://index.scala-lang.org/api/search?q=$n&target=$target&scalaVersion=$scalaVersion" + ) + .response(asJsonOrFail[Array[Project]]) + .send(CurlTryBackend()) + ).map(_.body) + + def project(org: String, repo: String): IO[ProjectDetails] = + IO.fromTry( + basicRequest + .get( + uri"https://index.scala-lang.org/api/project?organization=$org&repository=$repo" + ) + .response(asJsonOrFail[ProjectDetails]) + .send(CurlTryBackend()) + ).map(_.body) diff --git a/package-lock.json b/package-lock.json index 797d938..296d7ee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,50 +5,71 @@ "packages": { "": { "dependencies": { - "clipboardy": "^3.0.0", - "node-fetch": "^2.6.7", - "prompts": "^2.4.2" + "clipboardy": "^5.3.1", + "node-fetch": "^3.3.2" } }, - "node_modules/arch": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", - "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] + "node_modules/@sec-ant/readable-stream": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", + "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", + "license": "MIT" + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", + "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clipboard-image": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/clipboard-image/-/clipboard-image-0.1.0.tgz", + "integrity": "sha512-SWk7FgaXLNFld19peQ/rTe0n97lwR1WbkqxV6JKCAOh7U52AKV/PeMFCyt/8IhBdqyDA8rdyewQMKZqvWT5Akg==", + "license": "MIT", + "dependencies": { + "run-jxa": "^3.0.0" + }, + "bin": { + "clipboard-image": "cli.js" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/clipboardy": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-3.0.0.tgz", - "integrity": "sha512-Su+uU5sr1jkUy1sGRpLKjKrvEOVXgSgiSInwa/qeID6aJ07yh+5NWc3h2QfjHjBnfX4LhtFcuAWKUsJ3r+fjbg==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-5.3.1.tgz", + "integrity": "sha512-fPWgBqpp9ctiOQCkE5yjYGzv11ZU55g6ahEgr3COiio6dXdt1mbchCPXQrSR2Y9sZqfi8L7QD3+UosgXVIuPdg==", + "license": "MIT", "dependencies": { - "arch": "^2.2.0", - "execa": "^5.1.1", - "is-wsl": "^2.2.0" + "clipboard-image": "^0.1.0", + "execa": "^9.6.1", + "is-wayland": "^0.1.0", + "is-wsl": "^3.1.0", + "is64bit": "^2.0.0", + "powershell-utils": "^0.2.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -58,143 +79,373 @@ "node": ">= 8" } }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "node_modules/crypto-random-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", + "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", + "license": "MIT", "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" + "type-fest": "^1.0.1" }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/crypto-random-string/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/execa": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-9.6.1.tgz", + "integrity": "sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==", + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^4.0.0", + "cross-spawn": "^7.0.6", + "figures": "^6.1.0", + "get-stream": "^9.0.0", + "human-signals": "^8.0.1", + "is-plain-obj": "^4.1.0", + "is-stream": "^4.0.1", + "npm-run-path": "^6.0.0", + "pretty-ms": "^9.2.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^4.0.0", + "yoctocolors": "^2.1.1" + }, + "engines": { + "node": "^18.19.0 || >=20.5.0" + }, "funding": { "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/figures": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz", + "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==", + "license": "MIT", + "dependencies": { + "is-unicode-supported": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", + "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", + "license": "MIT", + "dependencies": { + "@sec-ant/readable-stream": "^0.4.1", + "is-stream": "^4.0.1" + }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz", + "integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==", + "license": "Apache-2.0", "engines": { - "node": ">=10.17.0" + "node": ">=18.18.0" } }, "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "license": "MIT", "bin": { "is-docker": "cli.js" }, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", + "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wayland": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-wayland/-/is-wayland-0.1.0.tgz", + "integrity": "sha512-QkbMsWkIfkrzOPxenwye0h56iAXirZYHG9eHVPb22fO9y+wPbaX/CHacOWBa/I++4ohTcByimhM1/nyCsH8KNA==", + "license": "MIT", + "engines": { + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "license": "MIT", "dependencies": { - "is-docker": "^2.0.0" + "is-inside-container": "^1.0.0" }, "engines": { - "node": ">=8" + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is64bit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is64bit/-/is64bit-2.0.0.tgz", + "integrity": "sha512-jv+8jaWCl0g2lSBkNSVXdzfBA0npK1HGC2KtWM9FumFRoGS94g3NbCCLVnCYHLjp4GrW2KZeeSTMo5ddtznmGw==", + "license": "MIT", + "dependencies": { + "system-architecture": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "node_modules/macos-version": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/macos-version/-/macos-version-6.0.0.tgz", + "integrity": "sha512-O2S8voA+pMfCHhBn/TIYDXzJ1qNHpPDU32oFxglKnVdJABiYYITt45oLkV9yhwA3E2FDwn3tQqUFrTsr1p3sBQ==", + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + }, "engines": { - "node": ">=6" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT" }, "node_modules/mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "license": "MIT", "engines": { "node": ">=6" } }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, "node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", "dependencies": { - "whatwg-url": "^5.0.0" + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" }, "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" } }, "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", + "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", + "license": "MIT", "dependencies": { - "path-key": "^3.0.0" + "path-key": "^4.0.0", + "unicorn-magic": "^0.3.0" }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/onetime": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" }, @@ -205,30 +456,172 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parse-ms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", + "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "node_modules/powershell-utils": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.2.0.tgz", + "integrity": "sha512-ZlsFlG7MtSFCoc5xreOvBAozCJ6Pf06opgJjh9ONEv418xpZSAzNjstD36C6+JwOnfSqOW/9uDkqKjezTdxZhw==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pretty-ms": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.0.tgz", + "integrity": "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==", + "license": "MIT", + "dependencies": { + "parse-ms": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-jxa": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/run-jxa/-/run-jxa-3.0.0.tgz", + "integrity": "sha512-4f2CrY7H+sXkKXJn/cE6qRA3z+NMVO7zvlZ/nUV0e62yWftpiLAfw5eV9ZdomzWd2TXWwEIiGjAT57+lWIzzvA==", + "license": "MIT", + "dependencies": { + "execa": "^5.1.1", + "macos-version": "^6.0.0", + "subsume": "^4.0.0", + "type-fest": "^2.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-jxa/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "license": "MIT", "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" }, "engines": { - "node": ">= 6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/run-jxa/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-jxa/node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/run-jxa/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-jxa/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/run-jxa/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, + "node_modules/run-jxa/node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -240,51 +633,116 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", + "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", + "license": "MIT", "engines": { - "node": ">=6" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + "node_modules/subsume": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/subsume/-/subsume-4.0.0.tgz", + "integrity": "sha512-BWnYJElmHbYZ/zKevy+TG+SsyoFCmRPDHJbR1MzLxkPOv1Jp/4hGhVUtP98s+wZBsBsHwCXvPTP0x287/WMjGg==", + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^5.0.0", + "unique-string": "^3.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + "node_modules/system-architecture": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/system-architecture/-/system-architecture-0.1.0.tgz", + "integrity": "sha512-ulAk51I9UVUyJgxlv9M6lFot2WP3e7t8Kz9+IS6D4rVba1tR9kON+Ey69f+1R4Q8cd45Lod6a4IcJIxnzGc/zA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unique-string": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", + "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", + "license": "MIT", "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" + "crypto-random-string": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "license": "MIT", + "engines": { + "node": ">= 8" } }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -294,6 +752,18 @@ "engines": { "node": ">= 8" } + }, + "node_modules/yoctocolors": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", + "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/package.json b/package.json index 927cd95..8e9e247 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,7 @@ { "type": "module", "dependencies": { - "clipboardy": "^3.0.0", - "node-fetch": "^2.6.7", - "prompts": "^2.4.2" + "clipboardy": "^5.3.1", + "node-fetch": "^3.3.2" } } diff --git a/project/build.properties b/project/build.properties index db1723b..7c95fc1 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.10.5 +sbt.version=1.12.13 diff --git a/project/plugins.sbt b/project/plugins.sbt index 26fd547..501730b 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,3 +1,6 @@ // addSbtPlugin("org.scalablytyped.converter" % "sbt-converter" % "1.0.0-beta40") -addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.17.0") +addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.22.0") +addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.5.12") addSbtPlugin("io.chrisdavenport" % "sbt-npm-package" % "0.1.2") +addSbtPlugin("com.eed3si9n" % "sbt-projectmatrix" % "0.11.0") +addSbtPlugin("com.indoorvivants" % "sbt-forge-native-binary" % "0.2.1") diff --git a/src/main/scala/dex/clipboard.scala b/src/main/scala/dex/clipboard.scala deleted file mode 100644 index 1369f22..0000000 --- a/src/main/scala/dex/clipboard.scala +++ /dev/null @@ -1,20 +0,0 @@ -package dex - -import scala.scalajs.js -import scala.scalajs.js.annotation.JSImport -import cats.effect.IO - -@JSImport("clipboardy", JSImport.Namespace) -@js.native -object clipboardy extends js.Object: - val default: Clipboard = js.native - -@js.native -trait Clipboard extends js.Any: - def write(s: String): js.Promise[Unit] = js.native - -def copyToClipboard(lines: Seq[String]): IO[Unit] = IO.fromPromise { - IO { - clipboardy.default.write(lines.mkString(System.lineSeparator())) - } -} diff --git a/src/main/scala/dex/scaladex.scala b/src/main/scala/dex/scaladex.scala deleted file mode 100644 index c3fe910..0000000 --- a/src/main/scala/dex/scaladex.scala +++ /dev/null @@ -1,51 +0,0 @@ -package dex - -import scala.scalajs.js -import scala.scalajs.js.JSConverters._ -import scala.scalajs.js.Thenable -import cats.effect.IO - -object scaladex: - - val target = "JVM" - val scalaVersion = "2.13" - - def search(name: String): IO[js.Array[Project]] = - val n = name.trim() - ioFetch - .get( - s"https://index.scala-lang.org/api/search?q=$n&target=$target&scalaVersion=$scalaVersion" - ) - .flatMap(_.json) - .map { json => - json.asInstanceOf[js.Array[Project]].filter { project => - project.repository.contains(n) || project.artifacts - .exists(_.contains(n)) - } - } - - def project(org: String, repo: String): IO[ProjectDetails] = - ioFetch - .get( - s"https://index.scala-lang.org/api/project?organization=$org&repository=$repo" - ) - .flatMap(_.json) - .map { json => - json.asInstanceOf[ProjectDetails] - } - end project - -end scaladex - -@js.native -trait Project extends js.Object: - def organization: String = js.native - def repository: String = js.native - def artifacts: js.Array[String] = js.native - -@js.native -trait ProjectDetails extends js.Object: - def artifacts: js.Array[String] - def versions: js.Array[String] - def groupId: String - def version: String diff --git a/src/main/scala/dex/util.scala b/src/main/scala/dex/util.scala deleted file mode 100644 index af0cb1f..0000000 --- a/src/main/scala/dex/util.scala +++ /dev/null @@ -1,12 +0,0 @@ -package dex - -import scala.scalajs.js -import js.annotation.JSImport - -/** Using this to discover the interface of objects, dynamically, to make sense - * of the differences between - */ -@JSImport("util", JSImport.Namespace) -@js.native -object util extends js.Any: - def inspect(any: js.Any): js.Any = js.native From 66e02b90cd6e1ae4c3c0b06f53f457f9108c3d83 Mon Sep 17 00:00:00 2001 From: Anton Sviridov Date: Wed, 24 Jun 2026 14:17:29 +0100 Subject: [PATCH 6/9] update to published cue4s --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 9bf5a4b..6a44787 100644 --- a/build.sbt +++ b/build.sbt @@ -49,7 +49,7 @@ lazy val dexsearch = projectMatrix .settings( libraryDependencies ++= Seq( "com.monovore" %%% "decline-effect" % "2.6.2", - "tech.neander" %%% "cue4s-cats-effect" % "dev" + "tech.neander" %%% "cue4s-cats-effect" % "0.0.13" ) ) From a5812d89a7195b996e885ad0c67ddd50910fb68d Mon Sep 17 00:00:00 2001 From: Anton Sviridov Date: Wed, 24 Jun 2026 14:26:09 +0100 Subject: [PATCH 7/9] install curl dev on linux --- .github/workflows/native.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/native.yml b/.github/workflows/native.yml index 1873af7..2f9d0a6 100644 --- a/.github/workflows/native.yml +++ b/.github/workflows/native.yml @@ -67,6 +67,7 @@ jobs: - name: Build the binary run: | + sudo apt-get install libcurl-dev sbt buildBinaryPlatformRelease - name: Upload artifacts From 1312c3cf9dcda9a195f2b9a7ce5a7ca155a779c1 Mon Sep 17 00:00:00 2001 From: Anton Sviridov Date: Wed, 24 Jun 2026 14:28:03 +0100 Subject: [PATCH 8/9] Fix --- .github/workflows/native.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/native.yml b/.github/workflows/native.yml index 2f9d0a6..3d73e62 100644 --- a/.github/workflows/native.yml +++ b/.github/workflows/native.yml @@ -67,7 +67,7 @@ jobs: - name: Build the binary run: | - sudo apt-get install libcurl-dev + sudo apt-get install libcurl4-openssl-dev sbt buildBinaryPlatformRelease - name: Upload artifacts From 2ec61e74f5e2d48a2517e5085d04fb6536430a36 Mon Sep 17 00:00:00 2001 From: Anton Sviridov Date: Wed, 24 Jun 2026 14:42:16 +0100 Subject: [PATCH 9/9] fix linux, disable windows --- .github/workflows/native.yml | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/.github/workflows/native.yml b/.github/workflows/native.yml index 3d73e62..837e829 100644 --- a/.github/workflows/native.yml +++ b/.github/workflows/native.yml @@ -67,7 +67,7 @@ jobs: - name: Build the binary run: | - sudo apt-get install libcurl4-openssl-dev + sudo apt-get install libcurl4-openssl-dev libidn2-dev sbt buildBinaryPlatformRelease - name: Upload artifacts @@ -91,27 +91,27 @@ jobs: - name: Setup git config run: git config --global core.autocrlf false - - uses: actions/checkout@v4 + # - uses: actions/checkout@v4 - - uses: actions/setup-java@v4 - with: - distribution: "temurin" - java-version: "21" + # - uses: actions/setup-java@v4 + # with: + # distribution: "temurin" + # java-version: "21" - - uses: coursier/cache-action@v6 + # - uses: coursier/cache-action@v6 - - uses: sbt/setup-sbt@v1 + # - uses: sbt/setup-sbt@v1 - - name: Cache SBT - uses: actions/cache@v5 - with: - path: | - %LocalAppData%\sbt\v2 - key: ${{ runner.os }}-sbt2 + # - name: Cache SBT + # uses: actions/cache@v5 + # with: + # path: | + # %LocalAppData%\sbt\v2 + # key: ${{ runner.os }}-sbt2 - - name: Build the binary - run: | - sbt buildBinaryPlatformRelease + # - name: Build the binary + # run: | + # sbt buildBinaryPlatformRelease # - name: Upload artifacts # uses: actions/upload-artifact@v4