From 9308f024e8499ad2a0c31701373ffc05781caec8 Mon Sep 17 00:00:00 2001 From: lostflydev Date: Thu, 2 Apr 2026 08:44:21 +0500 Subject: [PATCH 1/8] Add WASM support: --wasm flag with Node.js and Deno runtimes Implements scala-cli issue #3316: integrate WebAssembly with Scala CLI. - `--wasm` CLI flag and `//> using wasm` directive to enable WASM output - `--wasm-runtime ` option and `//> using wasmRuntime` directive Supported values: node (default), deno - `--deno-version`, `--wasmtime-version`, `--wasmer-version` options and corresponding directives for pinning runtime versions - **Node.js** (default): runs Scala.js WASM output with `--experimental-wasm-exnref` flag, requires Node.js >= 22 - **Deno**: runs Scala.js WASM output --- build.mill | 2 + .../scala/scala/build/internal/Runner.scala | 146 ++++- .../DirectivesPreprocessingUtils.scala | 3 +- .../scala/cli/commands/fix/BuiltInRules.scala | 1 + .../scala/scala/cli/commands/run/Run.scala | 515 +++++++++++------- .../cli/commands/shared/HelpGroups.scala | 3 +- .../cli/commands/shared/SharedOptions.scala | 41 +- .../cli/commands/shared/WasmOptions.scala | 32 ++ .../cli/internal/WasmRuntimeDownloader.scala | 104 ++++ .../build/errors/DenoNotFoundError.scala | 5 + .../errors/UnsupportedWasmRuntimeError.scala | 3 + .../build/preprocessing/directives/Wasm.scala | 52 ++ .../RunScalaJsTestDefinitions.scala | 277 +++++++++- .../scala/build/options/BuildOptions.scala | 1 + .../scala/build/options/WasmOptions.scala | 26 + .../scala/build/options/WasmRuntime.scala | 54 ++ website/docs/reference/cli-options.md | 26 + website/docs/reference/directives.md | 21 + 18 files changed, 1085 insertions(+), 227 deletions(-) create mode 100644 modules/cli/src/main/scala/scala/cli/commands/shared/WasmOptions.scala create mode 100644 modules/cli/src/main/scala/scala/cli/internal/WasmRuntimeDownloader.scala create mode 100644 modules/core/src/main/scala/scala/build/errors/DenoNotFoundError.scala create mode 100644 modules/core/src/main/scala/scala/build/errors/UnsupportedWasmRuntimeError.scala create mode 100644 modules/directives/src/main/scala/scala/build/preprocessing/directives/Wasm.scala create mode 100644 modules/options/src/main/scala/scala/build/options/WasmOptions.scala create mode 100644 modules/options/src/main/scala/scala/build/options/WasmRuntime.scala diff --git a/build.mill b/build.mill index 53e2c30df1..e67a2a754a 100644 --- a/build.mill +++ b/build.mill @@ -519,6 +519,8 @@ trait Core extends ScalaCliCrossSbtModule | def toolkitVersionForNative04 = "${Deps.toolkitVersionForNative04}" | def toolkitVersionForNative05 = "${Deps.toolkitVersionForNative05}" | + | def defaultDenoVersion = "2.1.4" + | | def typelevelOrganization = "${Deps.typelevelToolkit.dep.module.organization.value}" | def typelevelToolkitDefaultVersion = "${Deps.typelevelToolkitVersion}" | def typelevelToolkitMaxScalaNative = "${Deps.Versions.maxScalaNativeForTypelevelToolkit}" diff --git a/modules/build/src/main/scala/scala/build/internal/Runner.scala b/modules/build/src/main/scala/scala/build/internal/Runner.scala index 72c1b685d3..4ba52d017b 100644 --- a/modules/build/src/main/scala/scala/build/internal/Runner.scala +++ b/modules/build/src/main/scala/scala/build/internal/Runner.scala @@ -189,6 +189,60 @@ object Runner { run(command, logger, cwd = cwd, extraEnv = extraEnv) } + // Detects the major version of Node.js on PATH; cached for the JVM lifetime (lazy val). + // Returns None if node is not found or version cannot be parsed. + private lazy val nodeMajorVersion: Option[Int] = + try { + val process = new ProcessBuilder("node", "--version") + .redirectErrorStream(true) + .start() + val output = new String(process.getInputStream.readAllBytes()).trim + process.waitFor() + // Node version format: "v22.5.0" -> extract 22 + if (output.startsWith("v")) + output.drop(1).takeWhile(_.isDigit) match { + case s if s.nonEmpty => Some(s.toInt) + case _ => None + } + else None + } + catch { + case _: Exception => None + } + + // Node 24+ (V8 13+) has wasm-exnref enabled by default; older versions need --experimental-wasm-exnref. + private def nodeNeedsWasmFlag: Boolean = + nodeMajorVersion.forall(_ < 24) // true if unknown or < 24 + + // Detects the major version of Deno on PATH; cached for the JVM lifetime (lazy val). + // Returns None if deno is not found or version cannot be parsed. + private lazy val denoMajorVersion: Option[Int] = + try { + val process = new ProcessBuilder("deno", "--version") + .redirectErrorStream(true) + .start() + val output = new String(process.getInputStream.readAllBytes()).trim + process.waitFor() + // Deno version format: "deno 2.1.0 (release, aarch64-apple-darwin)\nv8 13.x\ntypescript 5.x" + // Extract major from first line + val firstLine = output.linesIterator.nextOption().getOrElse("") + val versionStr = firstLine.stripPrefix("deno ").takeWhile(c => c.isDigit || c == '.') + versionStr.takeWhile(_.isDigit) match { + case s if s.nonEmpty => Some(s.toInt) + case _ => None + } + } + catch { + case _: Exception => None + } + + // Deno 2.x+ bundles V8 13+ which has wasm-exnref enabled by default; no flag needed. + private def denoNeedsWasmFlag: Boolean = + denoMajorVersion.flatMap { major => + if (major >= 2) Some(false) // Deno 2.x+ has V8 13+ with wasm-exnref by default + else Some(true) + }.getOrElse(true) // true if unknown + private def endsWithCaseInsensitive(s: String, suffix: String): Boolean = s.length >= suffix.length && s.regionMatches(true, s.length - suffix.length, suffix, 0, suffix.length) @@ -221,11 +275,13 @@ object Runner { def jsCommand( entrypoint: File, args: Seq[String], - jsDom: Boolean = false + jsDom: Boolean = false, + emitWasm: Boolean = false ): Seq[String] = { - val nodePath = findInPath("node").fold("node")(_.toString) - val command = Seq(nodePath, entrypoint.getAbsolutePath) ++ args + val nodePath = findInPath("node").fold("node")(_.toString) + val nodeFlags = if (emitWasm && nodeNeedsWasmFlag) List("--experimental-wasm-exnref") else Nil + val command = Seq(nodePath) ++ nodeFlags ++ Seq(entrypoint.getAbsolutePath) ++ args if (jsDom) // FIXME We'd need to replicate what JSDOMNodeJSEnv does under-the-hood to get the command in that case. @@ -242,14 +298,16 @@ object Runner { allowExecve: Boolean = false, jsDom: Boolean = false, sourceMap: Boolean = false, - esModule: Boolean = false + esModule: Boolean = false, + emitWasm: Boolean = false ): Either[BuildException, Process] = either { val nodePath: String = value(findInPath("node") .map(_.toString) .toRight(NodeNotFoundError())) + val nodeFlags = if (emitWasm && nodeNeedsWasmFlag) List("--experimental-wasm-exnref") else Nil if !jsDom && allowExecve && Execve.available() then { - val command = Seq(nodePath, entrypoint.getAbsolutePath) ++ args + val command = Seq(nodePath) ++ nodeFlags ++ Seq(entrypoint.getAbsolutePath) ++ args logger.log( s"Running ${command.mkString(" ")}", @@ -265,12 +323,25 @@ object Runner { ) sys.error("should not happen") } + else if (emitWasm) { + // For WASM mode with ES modules, run node directly instead of NodeJSEnv. + // NodeJSEnv's stdin piping with "-" doesn't work with Input.ESModule. + val command = Seq(nodePath) ++ nodeFlags ++ Seq(entrypoint.getAbsolutePath) ++ args + + logger.log( + s"Running ${command.mkString(" ")}", + " Running" + System.lineSeparator() + + command.iterator.map(_ + System.lineSeparator()).mkString + ) + + new ProcessBuilder(command: _*).inheritIO().start() + } else { val nodeArgs = // Scala.js runs apps by piping JS to node. // If we need to pass arguments, we must first make the piped input explicit // with "-", and we pass the user's arguments after that. - if args.isEmpty then Nil else "-" :: args.toList + nodeFlags ++ (if args.isEmpty then Nil else "-" :: args.toList) val envJs = if jsDom then new JSDOMNodeJSEnv( @@ -307,6 +378,69 @@ object Runner { } } + def denoCommand( + entrypoint: File, + args: Seq[String], + denoPathOpt: Option[String] = None + ): Seq[String] = { + val denoPath = denoPathOpt.getOrElse(findInPath("deno").fold("deno")(_.toString)) + val denoFlags = Seq("run", "--allow-read") + Seq(denoPath) ++ denoFlags ++ Seq(entrypoint.getAbsolutePath) ++ args + } + + def runDeno( + entrypoint: File, + args: Seq[String], + logger: Logger, + allowExecve: Boolean = false, + emitWasm: Boolean = false, + denoPathOpt: Option[String] = None + ): Either[BuildException, Process] = either { + val denoPath: String = denoPathOpt.getOrElse { + value(findInPath("deno") + .map(_.toString) + .toRight(DenoNotFoundError())) + } + val denoFlags = Seq("run", "--allow-read") + val extraEnv = + if (emitWasm && denoNeedsWasmFlag) Map("DENO_V8_FLAGS" -> "--experimental-wasm-exnref") + else Map.empty + + if (allowExecve && Execve.available()) { + val command = Seq(denoPath) ++ denoFlags ++ Seq(entrypoint.getAbsolutePath) ++ args + + logger.log( + s"Running ${command.mkString(" ")}", + " Running" + System.lineSeparator() + + command.iterator.map(_ + System.lineSeparator()).mkString + ) + + logger.debug("execve available") + Execve.execve( + command.head, + "deno" +: command.tail.toArray, + (sys.env ++ extraEnv).toArray.sorted.map { case (k, v) => s"$k=$v" } + ) + sys.error("should not happen") + } + else { + val command = Seq(denoPath) ++ denoFlags ++ Seq(entrypoint.getAbsolutePath) ++ args + + logger.log( + s"Running ${command.mkString(" ")}", + " Running" + System.lineSeparator() + + command.iterator.map(_ + System.lineSeparator()).mkString + ) + + val builder = new ProcessBuilder(command*) + .inheritIO() + val env = builder.environment() + for ((k, v) <- extraEnv) + env.put(k, v) + builder.start() + } + } + def runNative( launcher: File, args: Seq[String], diff --git a/modules/build/src/main/scala/scala/build/preprocessing/directives/DirectivesPreprocessingUtils.scala b/modules/build/src/main/scala/scala/build/preprocessing/directives/DirectivesPreprocessingUtils.scala index 5b439b07fc..dfacd593fa 100644 --- a/modules/build/src/main/scala/scala/build/preprocessing/directives/DirectivesPreprocessingUtils.scala +++ b/modules/build/src/main/scala/scala/build/preprocessing/directives/DirectivesPreprocessingUtils.scala @@ -32,7 +32,8 @@ object DirectivesPreprocessingUtils { directives.ScalaVersion.handler, directives.Sources.handler, directives.Watching.handler, - directives.Tests.handler + directives.Tests.handler, + directives.Wasm.handler ).map(_.mapE(_.buildOptions)) val usingDirectiveWithReqsHandlers diff --git a/modules/cli/src/main/scala/scala/cli/commands/fix/BuiltInRules.scala b/modules/cli/src/main/scala/scala/cli/commands/fix/BuiltInRules.scala index 5c34b3368b..a2f92d2e42 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/fix/BuiltInRules.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/fix/BuiltInRules.scala @@ -387,6 +387,7 @@ object BuiltInRules extends CommandHelpers { JavaHome.handler.keys, ScalaNative.handler.keys, ScalaJs.handler.keys, + Wasm.handler.keys, ScalacOptions.handler.keys, JavaOptions.handler.keys, JavacOptions.handler.keys, diff --git a/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala b/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala index e22e6bedc8..af484d123d 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala @@ -12,13 +12,13 @@ import java.util.concurrent.atomic.AtomicReference import scala.build.* import scala.build.EitherCps.{either, value} import scala.build.Ops.* -import scala.build.errors.{BuildException, CompositeBuildException} +import scala.build.errors.{BuildException, CompositeBuildException, UnsupportedWasmRuntimeError} import scala.build.input.* import scala.build.internal.{Constants, Runner, ScalaJsLinkerConfig} import scala.build.internals.ConsoleUtils.ScalaCliConsole import scala.build.internals.ConsoleUtils.ScalaCliConsole.warnPrefix import scala.build.internals.EnvVar -import scala.build.options.{BuildOptions, JavaOpt, PackageType, Platform, Scope} +import scala.build.options.{BuildOptions, JavaOpt, PackageType, Platform, Scope, WasmRuntime} import scala.cli.CurrentParams import scala.cli.commands.package0.Package import scala.cli.commands.setupide.SetupIde @@ -28,7 +28,7 @@ import scala.cli.commands.util.BuildCommandHelpers.* import scala.cli.commands.util.{BuildCommandHelpers, RunHadoop, RunSpark} import scala.cli.commands.{CommandUtils, ScalaCommand, SpecificationLevel, WatchUtil} import scala.cli.config.Keys -import scala.cli.internal.ProcUtil +import scala.cli.internal.{ProcUtil, WasmRuntimeDownloader} import scala.cli.packaging.Library.fullClassPathMaybeAsJar import scala.cli.util.ArgHelpers.* import scala.cli.util.ConfigDbUtils @@ -474,229 +474,330 @@ object Run extends ScalaCommand[RunOptions] with BuildCommandHelpers { if shouldLogCrossInfo then logger.debug(s"Running build for ${crossBuildParams.asString}") val build = builds.head either { - build.options.platform.value match { - case Platform.JS => - val esModule = - build.options.scalaJsOptions.moduleKindStr.exists(m => m == "es" || m == "esmodule") - - val linkerConfig = builds.head.options.scalaJsOptions.linkerConfig(logger) - val jsDest = { - val delete = scratchDirOpt.isEmpty - scratchDirOpt.foreach(os.makeDir.all(_)) - os.temp( - dir = scratchDirOpt.orNull, - prefix = "main", - suffix = if esModule then ".mjs" else ".js", - deleteOnExit = delete - ) + val wasmOpts = build.options.wasmOptions + + // Check if WASM mode is requested + if wasmOpts.enabled then { + val runtime = wasmOpts.runtime + + if runtime.isJsBased then { + // JS-based WASM path - uses Scala.js WASM with JavaScript helpers (Node.js or Deno) + val esModule = true // WASM backend uses ES modules + scratchDirOpt.foreach(os.makeDir.all(_)) + val jsDest = os.temp( + dir = scratchDirOpt.orNull, + prefix = "main", + suffix = ".mjs", + deleteOnExit = scratchDirOpt.isEmpty + ) + + // Resolve Deno binary: check PATH first, download if needed + val denoPathOpt: Option[String] = runtime match { + case WasmRuntime.Deno => + val denoCmd = value(WasmRuntimeDownloader.denoCommand( + wasmOpts.finalDenoVersion, + build.options.archiveCache, + logger + )) + Some(denoCmd.head) + case _ => None } - val res = - Package.linkJs( - builds = builds, - dest = jsDest, - mainClassOpt = Some(mainClass), - addTestInitializer = false, - config = linkerConfig, - fullOpt = value(build.options.scalaJsOptions.fullOpt), - noOpt = build.options.scalaJsOptions.noOpt.getOrElse(false), - logger = logger, - scratchDirOpt = scratchDirOpt - ).map { outputPath => - val jsDom = build.options.scalaJsOptions.dom.getOrElse(false) - if showCommand then Left(Runner.jsCommand(outputPath.toIO, args, jsDom = jsDom)) - else { - val process = value { - Runner.runJs( - outputPath.toIO, - args, - logger, - allowExecve = effectiveAllowExecve, - jsDom = jsDom, - sourceMap = build.options.scalaJsOptions.emitSourceMaps, - esModule = esModule - ) - } - process.onExit().thenApply(_ => if os.exists(jsDest) then os.remove(jsDest)) - Right((process, None)) - } - } - value(res) - case Platform.Native => - val setupPython = build.options.notForBloopOptions.doSetupPython.getOrElse(false) - val (pythonExecutable, pythonLibraryPaths, pythonExtraEnv) = - if setupPython then { - val (exec, libPaths) = value { - val python = value(createPythonInstance().orPythonDetectionError) - val pythonPropertiesOrError = for { - paths <- python.nativeLibraryPaths - executable <- python.executable - } yield (Some(executable), paths) - logger.debug( - s"Python executable and native library paths: $pythonPropertiesOrError" - ) - pythonPropertiesOrError.orPythonDetectionError + + val linkerConfig = build.options.scalaJsOptions.linkerConfig(logger) + .copy(emitWasm = true, moduleKind = ScalaJsLinkerConfig.ModuleKind.ESModule) + + val res = Package.linkJs( + builds = builds, + dest = jsDest, + mainClassOpt = Some(mainClass), + addTestInitializer = false, + config = linkerConfig, + fullOpt = value(build.options.scalaJsOptions.fullOpt), + noOpt = build.options.scalaJsOptions.noOpt.getOrElse(false), + logger = logger, + scratchDirOpt = scratchDirOpt + ).map { outputPath => + if showCommand then + runtime match { + case WasmRuntime.Deno => + Left(Runner.denoCommand(outputPath.toIO, args, denoPathOpt = denoPathOpt)) + case _ => + Left(Runner.jsCommand(outputPath.toIO, args, jsDom = false, emitWasm = true)) } - // Putting the workspace in PYTHONPATH, see - // https://github.com/VirtusLab/scala-cli/pull/1616#issuecomment-1333283174 - // for context. - (exec, libPaths, pythonPathEnv(builds.head.inputs.workspace)) - } - else - (None, Nil, Map()) - // seems conda doesn't add the lib directory to LD_LIBRARY_PATH (see conda/conda#308), - // which prevents apps from finding libpython for example, so we update it manually here - val libraryPathsEnv = - if pythonLibraryPaths.isEmpty then Map.empty else { - val prependTo = - if Properties.isWin then EnvVar.Misc.path.name - else if Properties.isMac then EnvVar.Misc.dyldLibraryPath.name - else EnvVar.Misc.ldLibraryPath.name - val currentOpt = Option(System.getenv(prependTo)) - val currentEntries = currentOpt - .map(_.split(File.pathSeparator).toSet) - .getOrElse(Set.empty) - val additionalEntries = pythonLibraryPaths.filter(!currentEntries.contains(_)) - if additionalEntries.isEmpty then Map.empty - else { - val newValue = (additionalEntries.iterator ++ currentOpt.iterator).mkString( - File.pathSeparator - ) - Map(prependTo -> newValue) + val process = value { + runtime match { + case WasmRuntime.Deno => + Runner.runDeno( + outputPath.toIO, + args, + logger, + allowExecve = effectiveAllowExecve, + emitWasm = true, + denoPathOpt = denoPathOpt + ) + case _ => + Runner.runJs( + outputPath.toIO, + args, + logger, + allowExecve = effectiveAllowExecve, + jsDom = false, + sourceMap = build.options.scalaJsOptions.emitSourceMaps, + esModule = esModule, + emitWasm = true + ) + } } + process.onExit().thenApply(_ => if os.exists(jsDest) then os.remove(jsDest)) + Right((process, None)) } - val programNameEnv = - pythonExecutable.fold(Map.empty)(py => Map("SCALAPY_PYTHON_PROGRAMNAME" -> py)) - val extraEnv = libraryPathsEnv ++ programNameEnv ++ pythonExtraEnv - val maybeResult = withNativeLauncher( - builds, - mainClass, - logger - ) { launcher => - if showCommand then - Left( - extraEnv.toVector.sorted.map { case (k, v) => s"$k=$v" } ++ - Seq(launcher.toString) ++ - args - ) - else { - val proc = Runner.runNative( - launcher = launcher.toIO, - args = args, - logger = logger, - allowExecve = effectiveAllowExecve, - extraEnv = extraEnv + } + value(res) + } + else { + // Standalone WASM runtimes - not yet supported. + // Scala.js currently produces JS-dependent WASM output. + // Standalone support requires upstream Scala.js changes (scala-js/scala-js#4991). + val runtimeName = runtime.name + val extraNote = runtime match { + case WasmRuntime.Wasmer => + " Note: Wasmer does not yet support WasmGC, which is required for Scala WASM output." + case _ => "" + } + value(Left(new UnsupportedWasmRuntimeError( + s"Standalone WASM runtime '$runtimeName' is not yet supported." + + s"$extraNote" + + " Scala.js currently produces JavaScript-dependent WASM output." + + " Standalone WASM support is tracked at: https://github.com/scala-js/scala-js/issues/4991" + + " Use --wasm-runtime node (default) or --wasm-runtime deno for JS-based WASM execution." + ))) + } + } + else + build.options.platform.value match { + case Platform.JS => + val esModule = + build.options.scalaJsOptions.moduleKindStr.exists(m => m == "es" || m == "esmodule") + + val linkerConfig = build.options.scalaJsOptions.linkerConfig(logger) + val jsDest = { + val delete = scratchDirOpt.isEmpty + scratchDirOpt.foreach(os.makeDir.all(_)) + os.temp( + dir = scratchDirOpt.orNull, + prefix = "main", + suffix = if esModule then ".mjs" else ".js", + deleteOnExit = delete ) - Right((proc, None)) } - } - value(maybeResult) - case Platform.JVM => - def fwd(s: String): String = s.replace('\\', '/') - def base(s: String): String = fwd(s).replaceAll(".*/", "") - runMode match { - case RunMode.Default => - val sourceFiles = builds.head.inputs.sourceFiles().map { - case s: ScalaFile => fwd(s.path.toString) - case s: Script => fwd(s.path.toString) - case s: MarkdownFile => fwd(s.path.toString) - case _: SbtFile => "" - case s: OnDisk => fwd(s.path.toString) - case null => "" - }.filter(_.nonEmpty).distinct - val sources = sourceFiles.mkString(File.pathSeparator) - val sourceNames = sourceFiles.map(base).mkString(File.pathSeparator) - - val baseJavaProps = build.options.javaOptions.javaOpts.toSeq.map(_.value.value) - ++ Seq(s"-Dscala.sources=$sources", s"-Dscala.source.names=$sourceNames") - val setupPython = build.options.notForBloopOptions.doSetupPython.getOrElse(false) - val (pythonJavaProps, pythonExtraEnv) = - if setupPython then { - val scalapyProps = value { - val python = value(createPythonInstance().orPythonDetectionError) - val propsOrError = python.scalapyProperties - logger.debug(s"Python Java properties: $propsOrError") - propsOrError.orPythonDetectionError - } - val props = scalapyProps.toVector.sorted.map { - case (k, v) => s"-D$k=$v" + val res = + Package.linkJs( + builds = builds, + dest = jsDest, + mainClassOpt = Some(mainClass), + addTestInitializer = false, + config = linkerConfig, + fullOpt = value(build.options.scalaJsOptions.fullOpt), + noOpt = build.options.scalaJsOptions.noOpt.getOrElse(false), + logger = logger, + scratchDirOpt = scratchDirOpt + ).map { outputPath => + val jsDom = build.options.scalaJsOptions.dom.getOrElse(false) + if showCommand then Left(Runner.jsCommand(outputPath.toIO, args, jsDom = jsDom)) + else { + val process = value { + Runner.runJs( + outputPath.toIO, + args, + logger, + allowExecve = effectiveAllowExecve, + jsDom = jsDom, + sourceMap = build.options.scalaJsOptions.emitSourceMaps, + esModule = esModule + ) } - // Putting the workspace in PYTHONPATH, see - // https://github.com/VirtusLab/scala-cli/pull/1616#issuecomment-1333283174 - // for context. - (props, pythonPathEnv(build.inputs.workspace)) + process.onExit().thenApply(_ => if os.exists(jsDest) then os.remove(jsDest)) + Right((process, None)) } - else - (Nil, Map.empty[String, String]) - val allJavaOpts = pythonJavaProps ++ baseJavaProps - if showCommand then - Left { - Runner.jvmCommand( - build.options.javaHome().value.javaCommand, - allJavaOpts, - builds.flatMap(_.fullClassPathMaybeAsJar(asJar)).distinct, - mainClass, - args, - extraEnv = pythonExtraEnv, - useManifest = build.options.notForBloopOptions.runWithManifest, - scratchDirOpt = scratchDirOpt + } + value(res) + case Platform.Native => + val setupPython = build.options.notForBloopOptions.doSetupPython.getOrElse(false) + val (pythonExecutable, pythonLibraryPaths, pythonExtraEnv) = + if setupPython then { + val (exec, libPaths) = value { + val python = value(createPythonInstance().orPythonDetectionError) + val pythonPropertiesOrError = for { + paths <- python.nativeLibraryPaths + executable <- python.executable + } yield (Some(executable), paths) + logger.debug( + s"Python executable and native library paths: $pythonPropertiesOrError" ) + pythonPropertiesOrError.orPythonDetectionError } - else { - val proc = Runner.runJvm( - javaCommand = build.options.javaHome().value.javaCommand, - javaArgs = allJavaOpts, - classPath = builds.flatMap(_.fullClassPathMaybeAsJar(asJar)).distinct, - mainClass = mainClass, - args = args, - logger = logger, - allowExecve = effectiveAllowExecve, - extraEnv = pythonExtraEnv, - useManifest = build.options.notForBloopOptions.runWithManifest, - scratchDirOpt = scratchDirOpt - ) - Right((proc, None)) + // Putting the workspace in PYTHONPATH, see + // https://github.com/VirtusLab/scala-cli/pull/1616#issuecomment-1333283174 + // for context. + (exec, libPaths, pythonPathEnv(builds.head.inputs.workspace)) } - case mode: RunMode.SparkSubmit => - value { - RunSpark.run( - builds = builds, - mainClass = mainClass, - args = args, - submitArgs = mode.submitArgs, - logger = logger, - allowExecve = effectiveAllowExecve, - showCommand = showCommand, - scratchDirOpt = scratchDirOpt - ) + else + (None, Nil, Map()) + // seems conda doesn't add the lib directory to LD_LIBRARY_PATH (see conda/conda#308), + // which prevents apps from finding libpython for example, so we update it manually here + val libraryPathsEnv = + if pythonLibraryPaths.isEmpty then Map.empty + else { + val prependTo = + if Properties.isWin then EnvVar.Misc.path.name + else if Properties.isMac then EnvVar.Misc.dyldLibraryPath.name + else EnvVar.Misc.ldLibraryPath.name + val currentOpt = Option(System.getenv(prependTo)) + val currentEntries = currentOpt + .map(_.split(File.pathSeparator).toSet) + .getOrElse(Set.empty) + val additionalEntries = pythonLibraryPaths.filter(!currentEntries.contains(_)) + if additionalEntries.isEmpty then Map.empty + else { + val newValue = (additionalEntries.iterator ++ currentOpt.iterator).mkString( + File.pathSeparator + ) + Map(prependTo -> newValue) + } } - case mode: RunMode.StandaloneSparkSubmit => - value { - RunSpark.runStandalone( - builds = builds, - mainClass = mainClass, - args = args, - submitArgs = mode.submitArgs, - logger = logger, - allowExecve = effectiveAllowExecve, - showCommand = showCommand, - scratchDirOpt = scratchDirOpt + val programNameEnv = + pythonExecutable.fold(Map.empty)(py => Map("SCALAPY_PYTHON_PROGRAMNAME" -> py)) + val extraEnv = libraryPathsEnv ++ programNameEnv ++ pythonExtraEnv + val maybeResult = withNativeLauncher( + builds, + mainClass, + logger + ) { launcher => + if showCommand then + Left( + extraEnv.toVector.sorted.map { case (k, v) => s"$k=$v" } ++ + Seq(launcher.toString) ++ + args ) - } - case RunMode.HadoopJar => - value { - RunHadoop.run( - builds = builds, - mainClass = mainClass, + else { + val proc = Runner.runNative( + launcher = launcher.toIO, args = args, logger = logger, allowExecve = effectiveAllowExecve, - showCommand = showCommand, - scratchDirOpt = scratchDirOpt + extraEnv = extraEnv ) + Right((proc, None)) } - } - } + } + value(maybeResult) + case Platform.JVM => + def fwd(s: String): String = s.replace('\\', '/') + def base(s: String): String = fwd(s).replaceAll(".*/", "") + runMode match { + case RunMode.Default => + val sourceFiles = builds.head.inputs.sourceFiles().map { + case s: ScalaFile => fwd(s.path.toString) + case s: Script => fwd(s.path.toString) + case s: MarkdownFile => fwd(s.path.toString) + case s: OnDisk => fwd(s.path.toString) + case s => s.getClass.getName + }.filter(_.nonEmpty).distinct + val sources = sourceFiles.mkString(File.pathSeparator) + val sourceNames = sourceFiles.map(base).mkString(File.pathSeparator) + + val baseJavaProps = build.options.javaOptions.javaOpts.toSeq.map(_.value.value) + ++ Seq(s"-Dscala.sources=$sources", s"-Dscala.source.names=$sourceNames") + val setupPython = + build.options.notForBloopOptions.doSetupPython.getOrElse(false) + val (pythonJavaProps, pythonExtraEnv) = + if setupPython then { + val scalapyProps = value { + val python = value(createPythonInstance().orPythonDetectionError) + val propsOrError = python.scalapyProperties + logger.debug(s"Python Java properties: $propsOrError") + propsOrError.orPythonDetectionError + } + val props = scalapyProps.toVector.sorted.map { + case (k, v) => s"-D$k=$v" + } + // Putting the workspace in PYTHONPATH, see + // https://github.com/VirtusLab/scala-cli/pull/1616#issuecomment-1333283174 + // for context. + (props, pythonPathEnv(build.inputs.workspace)) + } + else + (Nil, Map.empty[String, String]) + val allJavaOpts = pythonJavaProps ++ baseJavaProps + if showCommand then + Left { + Runner.jvmCommand( + build.options.javaHome().value.javaCommand, + allJavaOpts, + builds.flatMap(_.fullClassPathMaybeAsJar(asJar)).distinct, + mainClass, + args, + extraEnv = pythonExtraEnv, + useManifest = build.options.notForBloopOptions.runWithManifest, + scratchDirOpt = scratchDirOpt + ) + } + else { + val proc = Runner.runJvm( + javaCommand = build.options.javaHome().value.javaCommand, + javaArgs = allJavaOpts, + classPath = builds.flatMap(_.fullClassPathMaybeAsJar(asJar)).distinct, + mainClass = mainClass, + args = args, + logger = logger, + allowExecve = effectiveAllowExecve, + extraEnv = pythonExtraEnv, + useManifest = build.options.notForBloopOptions.runWithManifest, + scratchDirOpt = scratchDirOpt + ) + Right((proc, None)) + } + case mode: RunMode.SparkSubmit => + value { + RunSpark.run( + builds = builds, + mainClass = mainClass, + args = args, + submitArgs = mode.submitArgs, + logger = logger, + allowExecve = effectiveAllowExecve, + showCommand = showCommand, + scratchDirOpt = scratchDirOpt + ) + } + case mode: RunMode.StandaloneSparkSubmit => + value { + RunSpark.runStandalone( + builds = builds, + mainClass = mainClass, + args = args, + submitArgs = mode.submitArgs, + logger = logger, + allowExecve = effectiveAllowExecve, + showCommand = showCommand, + scratchDirOpt = scratchDirOpt + ) + } + case RunMode.HadoopJar => + value { + RunHadoop.run( + builds = builds, + mainClass = mainClass, + args = args, + logger = logger, + allowExecve = effectiveAllowExecve, + showCommand = showCommand, + scratchDirOpt = scratchDirOpt + ) + } + } + } } } .sequence diff --git a/modules/cli/src/main/scala/scala/cli/commands/shared/HelpGroups.scala b/modules/cli/src/main/scala/scala/cli/commands/shared/HelpGroups.scala index 8f6099a324..c943c3c904 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/shared/HelpGroups.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/shared/HelpGroups.scala @@ -17,7 +17,7 @@ enum HelpGroup: Scala, ScalaJs, ScalaNative, Secret, Signing, SuppressWarnings, SourceGenerator, Test, Uninstall, Update, - Watch, Windows, + Wasm, Watch, Windows, Version override def toString: String = this match @@ -30,6 +30,7 @@ enum HelpGroup: case SuppressWarnings => "Suppress warnings" case SourceGenerator => "Source generator" case ProjectVersion => "Project version" + case Wasm => "WebAssembly" case e => e.productPrefix enum HelpCommandGroup: diff --git a/modules/cli/src/main/scala/scala/cli/commands/shared/SharedOptions.scala b/modules/cli/src/main/scala/scala/cli/commands/shared/SharedOptions.scala index 71dd29d1f3..c48dbc43bd 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/shared/SharedOptions.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/shared/SharedOptions.scala @@ -57,6 +57,8 @@ final case class SharedOptions( js: ScalaJsOptions = ScalaJsOptions(), @Recurse native: ScalaNativeOptions = ScalaNativeOptions(), + @Recurse + wasmOptions: WasmOptions = WasmOptions(), @Recurse compilationServer: SharedCompilationServerOptions = SharedCompilationServerOptions(), @Recurse @@ -311,6 +313,16 @@ final case class SharedOptions( ) } + private def buildWasmOptions(opts: WasmOptions): options.WasmOptions = { + import opts._ + options.WasmOptions( + enabled = wasm, + runtime = + wasmRuntime.flatMap(options.WasmRuntime.parse).getOrElse(options.WasmRuntime.default), + denoVersion = denoVersion + ) + } + lazy val scalacOptionsFromFiles: List[String] = scalac.argsFiles.flatMap(argFile => ArgSplitter.splitToArgs(os.read(os.Path(argFile.file, os.pwd))) @@ -335,21 +347,27 @@ final case class SharedOptions( case _ => } val parsedPlatform = platform.map(Platform.normalize).flatMap(Platform.parse) - val platformOpt = value { - (parsedPlatform, js.js, native.native) match { - case (Some(p: Platform.JS.type), _, false) => Right(Some(p)) - case (Some(p: Platform.Native.type), false, _) => Right(Some(p)) - case (Some(p: Platform.JVM.type), false, false) => Right(Some(p)) - case (Some(p), _, _) => - val jsSeq = if (js.js) Seq(Platform.JS) else Seq.empty + // WASM mode requires Scala.js platform for compilation + val wasmEnabled = wasmOptions.wasm + val platformOpt = value { + (parsedPlatform, js.js, native.native, wasmEnabled) match { + case (Some(p: Platform.JS.type), _, false, _) => Right(Some(p)) + case (Some(p: Platform.Native.type), false, _, false) => Right(Some(p)) + case (Some(p: Platform.JVM.type), false, false, false) => Right(Some(p)) + case (Some(p), _, _, _) => + val jsSeq = if (js.js || wasmEnabled) Seq(Platform.JS) else Seq.empty val nativeSeq = if (native.native) Seq(Platform.Native) else Seq.empty val platformsSeq = Seq(p) ++ jsSeq ++ nativeSeq Left(new AmbiguousPlatformError(platformsSeq.distinct.map(_.toString))) - case (_, true, true) => + case (_, true, true, _) => Left(new AmbiguousPlatformError(Seq(Platform.JS.toString, Platform.Native.toString))) - case (_, true, _) => Right(Some(Platform.JS)) - case (_, _, true) => Right(Some(Platform.Native)) - case _ => Right(None) + case (_, _, true, true) => + Left(new AmbiguousPlatformError(Seq(Platform.Native.toString, "WASM (requires JS)"))) + case (_, true, _, _) => Right(Some(Platform.JS)) + case (_, _, _, true) => + Right(Some(Platform.JS)) // WASM requires JS compilation (Scala.js WASM backend) + case (_, _, true, _) => Right(Some(Platform.Native)) + case _ => Right(None) } } val (assumedSourceJars, extraRegularJarsAndClasspath) = @@ -436,6 +454,7 @@ final case class SharedOptions( ), scalaJsOptions = scalaJsOptions(js), scalaNativeOptions = snOpts, + wasmOptions = buildWasmOptions(wasmOptions), javaOptions = value(scala.cli.commands.util.JvmUtils.javaOptions(jvm)), jmhOptions = scala.build.options.JmhOptions( jmhVersion = benchmarking.jmhVersion, diff --git a/modules/cli/src/main/scala/scala/cli/commands/shared/WasmOptions.scala b/modules/cli/src/main/scala/scala/cli/commands/shared/WasmOptions.scala new file mode 100644 index 0000000000..d8793afaa2 --- /dev/null +++ b/modules/cli/src/main/scala/scala/cli/commands/shared/WasmOptions.scala @@ -0,0 +1,32 @@ +package scala.cli.commands.shared + +import caseapp.* +import com.github.plokhotnyuk.jsoniter_scala.core.* +import com.github.plokhotnyuk.jsoniter_scala.macros.* + +import scala.cli.commands.tags + +// format: off +final case class WasmOptions( + @Group(HelpGroup.Scala.toString) + @Tag(tags.experimental) + @HelpMessage("Enable WebAssembly output (Scala.js WASM backend). Uses Node.js by default. To show more options for WASM pass `--help-wasm`") + wasm: Boolean = false, + + @Group(HelpGroup.Wasm.toString) + @Tag(tags.experimental) + @HelpMessage("WASM runtime to use: node (default), deno. Standalone runtimes (wasmtime, wasmedge) planned for future releases.") + wasmRuntime: Option[String] = None, + + @Group(HelpGroup.Wasm.toString) + @Tag(tags.experimental) + @HelpMessage("Version of Deno to use. If Deno is not found on PATH, it will be downloaded automatically.") + denoVersion: Option[String] = None +) +// format: on + +object WasmOptions { + implicit lazy val parser: Parser[WasmOptions] = Parser.derive + implicit lazy val help: Help[WasmOptions] = Help.derive + implicit lazy val jsonCodec: JsonValueCodec[WasmOptions] = JsonCodecMaker.make +} diff --git a/modules/cli/src/main/scala/scala/cli/internal/WasmRuntimeDownloader.scala b/modules/cli/src/main/scala/scala/cli/internal/WasmRuntimeDownloader.scala new file mode 100644 index 0000000000..751e087034 --- /dev/null +++ b/modules/cli/src/main/scala/scala/cli/internal/WasmRuntimeDownloader.scala @@ -0,0 +1,104 @@ +package scala.cli.internal + +import coursier.cache.ArchiveCache +import coursier.util.Task + +import java.util.Locale + +import scala.build.EitherCps.{either, value} +import scala.build.Logger +import scala.build.errors.BuildException +import scala.build.internal.FetchExternalBinary +import scala.util.Properties + +/** Resolves Deno binary for WASM execution. + * + * Deno is first looked up on the system PATH. If not found, it is downloaded from GitHub releases + * and cached via Coursier's ArchiveCache. + */ +object WasmRuntimeDownloader { + + /** Returns the command to run Deno. + * + * First checks system PATH, otherwise downloads the binary. + */ + def denoCommand( + version: String, + archiveCache: ArchiveCache[Task], + logger: Logger + ): Either[BuildException, Seq[String]] = either { + findOnPath("deno") match { + case Some(path) => + logger.debug(s"Using system deno at: $path") + Seq(path) + case None => + logger.message(s"Deno not found on PATH, downloading v$version...") + val binary = value(fetchDeno(version, archiveCache, logger)) + Seq(binary.toString) + } + } + + /** Find an executable on the system PATH */ + private def findOnPath(name: String): Option[String] = { + val exeName = if (Properties.isWin) s"$name.exe" else name + sys.env.get("PATH").flatMap { pathEnv => + pathEnv.split(java.io.File.pathSeparator).view.map { dir => + val file = new java.io.File(dir, exeName) + if (file.exists() && file.canExecute) Some(file.getAbsolutePath) + else None + }.find(_.isDefined).flatten + } + } + + private def detectOs(win: String, linux: String, mac: String): Either[BuildException, String] = + if (Properties.isWin) Right(win) + else if (Properties.isLinux) Right(linux) + else if (Properties.isMac) Right(mac) + else Left(new WasmRuntimeDownloadError(s"Unsupported OS: ${sys.props("os.name")}")) + + private def detectArch64(x86_64: String, aarch64: String): Either[BuildException, String] = + sys.props("os.arch").toLowerCase(Locale.ROOT) match { + case "amd64" | "x86_64" => Right(x86_64) + case "aarch64" | "arm64" => Right(aarch64) + case other => Left(new WasmRuntimeDownloadError(s"Unsupported architecture: $other")) + } + + /** Fetches Deno binary for the current platform. + * + * Deno releases are at: + * https://github.com/denoland/deno/releases/download/v{version}/deno-{platform}.zip + */ + private def fetchDeno( + version: String, + archiveCache: ArchiveCache[Task], + logger: Logger + ): Either[BuildException, os.Path] = either { + val platform = value(denoPlatform) + val url = s"https://github.com/denoland/deno/releases/download/v$version/deno-$platform.zip" + + val binaryOpt = value { + FetchExternalBinary.fetchLauncher( + url = url, + changing = false, + archiveCache = archiveCache, + logger = logger, + launcherPrefix = "deno", + launcherPathOpt = None, + makeExecutable = true + ) + } + + binaryOpt.getOrElse { + value(Left(new WasmRuntimeDownloadError(s"Could not download Deno v$version for $platform"))) + } + } + + /** Platform suffix for Deno downloads */ + private def denoPlatform: Either[BuildException, String] = either { + val arch = value(detectArch64("x86_64", "aarch64")) + val os = value(detectOs("pc-windows-msvc", "unknown-linux-gnu", "apple-darwin")) + s"$arch-$os" + } +} + +class WasmRuntimeDownloadError(message: String) extends BuildException(message) diff --git a/modules/core/src/main/scala/scala/build/errors/DenoNotFoundError.scala b/modules/core/src/main/scala/scala/build/errors/DenoNotFoundError.scala new file mode 100644 index 0000000000..4566e346a4 --- /dev/null +++ b/modules/core/src/main/scala/scala/build/errors/DenoNotFoundError.scala @@ -0,0 +1,5 @@ +package scala.build.errors + +final class DenoNotFoundError extends BuildException( + "Deno was not found on the PATH. Install Deno from https://deno.land/ or use --wasm-runtime node" + ) diff --git a/modules/core/src/main/scala/scala/build/errors/UnsupportedWasmRuntimeError.scala b/modules/core/src/main/scala/scala/build/errors/UnsupportedWasmRuntimeError.scala new file mode 100644 index 0000000000..b663b6a956 --- /dev/null +++ b/modules/core/src/main/scala/scala/build/errors/UnsupportedWasmRuntimeError.scala @@ -0,0 +1,3 @@ +package scala.build.errors + +final class UnsupportedWasmRuntimeError(message: String) extends BuildException(message) diff --git a/modules/directives/src/main/scala/scala/build/preprocessing/directives/Wasm.scala b/modules/directives/src/main/scala/scala/build/preprocessing/directives/Wasm.scala new file mode 100644 index 0000000000..361fcc32ab --- /dev/null +++ b/modules/directives/src/main/scala/scala/build/preprocessing/directives/Wasm.scala @@ -0,0 +1,52 @@ +package scala.build.preprocessing.directives + +import scala.build.Positioned +import scala.build.directives.* +import scala.build.errors.BuildException +import scala.build.options.{BuildOptions, Platform, ScalaOptions, WasmOptions, WasmRuntime} +import scala.cli.commands.SpecificationLevel + +@DirectiveGroupName("WASM options") +@DirectiveExamples("//> using wasm") +@DirectiveExamples("//> using wasmRuntime node") +@DirectiveExamples("//> using wasmRuntime deno") +@DirectiveExamples("//> using denoVersion 2.1.4") +@DirectiveUsage( + "//> using wasm|wasmRuntime|denoVersion _value_", + """ + |`//> using wasm` _true|false_ + | + |`//> using wasm` + | + |`//> using wasmRuntime` _node|deno|wasmtime|wasmedge|wasmer_ + | + |`//> using denoVersion` _value_ + |""".stripMargin +) +@DirectiveDescription("Add WebAssembly options") +@DirectiveLevel(SpecificationLevel.EXPERIMENTAL) +final case class Wasm( + wasm: Option[Boolean] = None, + wasmRuntime: Option[String] = None, + denoVersion: Option[String] = None +) extends HasBuildOptions { + def buildOptions: Either[BuildException, BuildOptions] = { + val parsedRuntime = wasmRuntime.flatMap(WasmRuntime.parse) + val wasmOptions = WasmOptions( + enabled = wasm.getOrElse(false), + runtime = parsedRuntime.getOrElse(WasmRuntime.default), + denoVersion = denoVersion + ) + // When WASM is enabled, force Platform.JS (Scala.js WASM backend requires JS compilation) + val scalaOptions = + if (wasm.getOrElse(false)) + ScalaOptions(platform = Some(Positioned.none(Platform.JS))) + else + ScalaOptions() + Right(BuildOptions(scalaOptions = scalaOptions, wasmOptions = wasmOptions)) + } +} + +object Wasm { + val handler: DirectiveHandler[Wasm] = DirectiveHandler.derive +} diff --git a/modules/integration/src/test/scala/scala/cli/integration/RunScalaJsTestDefinitions.scala b/modules/integration/src/test/scala/scala/cli/integration/RunScalaJsTestDefinitions.scala index 4745787924..8436bc2e0f 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/RunScalaJsTestDefinitions.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/RunScalaJsTestDefinitions.scala @@ -325,11 +325,286 @@ trait RunScalaJsTestDefinitions { this: RunTestDefinitions => .call(cwd = root).out.trim() val path = absOutDir / "main.wasm" expect(os.exists(path)) + } + } + + test("Run with --wasm flag") { + val inputs = TestInputs( + os.rel / "Hello.scala" -> + """object Hello { + | def main(args: Array[String]): Unit = println("Hello from WASM!") + |} + |""".stripMargin + ) + inputs.fromRoot { root => + val output = os.proc( + TestUtil.cli, + "--power", + "run", + "Hello.scala", + "--wasm", + "--wasm-runtime", + "node", + extraOptions + ).call(cwd = root).out.trim() + expect(output == "Hello from WASM!") + } + } - // TODO : Run WASM using node. Requires node 22. + test("Run with --wasm uses Node.js by default") { + val inputs = TestInputs( + os.rel / "Hello.scala" -> + """object Hello { + | def main(args: Array[String]): Unit = println("Hello default WASM!") + |} + |""".stripMargin + ) + inputs.fromRoot { root => + val output = os.proc( + TestUtil.cli, + "--power", + "run", + "Hello.scala", + "--wasm", + extraOptions + ).call(cwd = root).out.trim() + expect(output == "Hello default WASM!") } } + test("Run with //> using wasm directive") { + val inputs = TestInputs( + os.rel / "Hello.scala" -> + """//> using wasm + |//> using wasmRuntime node + |object Hello { + | def main(args: Array[String]): Unit = println("Hello from WASM directive!") + |} + |""".stripMargin + ) + inputs.fromRoot { root => + val output = os.proc( + TestUtil.cli, + "--power", + "run", + "Hello.scala", + extraOptions + ).call(cwd = root).out.trim() + expect(output == "Hello from WASM directive!") + } + } + + test("WASM passes arguments to program") { + // Scala.js always passes an empty Array[String] to main(args), + // so we must read process.argv directly via JS interop. + val inputs = TestInputs( + os.rel / "Hello.scala" -> + """import scala.scalajs.js + |import scala.scalajs.js.Dynamic.global + |object Hello { + | def main(args: Array[String]): Unit = { + | val argv = global.process.argv.asInstanceOf[js.Array[String]].drop(2).toSeq + | println(argv.mkString(" ")) + | } + |} + |""".stripMargin + ) + inputs.fromRoot { root => + val output = os.proc( + TestUtil.cli, + "--power", + "run", + "Hello.scala", + "--wasm", + "--wasm-runtime", + "node", + extraOptions, + "--", + "foo", + "bar", + "baz" + ).call(cwd = root).out.trim() + expect(output == "foo bar baz") + } + } + + for (runtime <- Seq("wasmtime", "wasmedge", "wasmer")) + test(s"Unsupported WASM runtime '$runtime' gives clear error") { + val inputs = TestInputs( + os.rel / "Hello.scala" -> + """object Hello { + | def main(args: Array[String]): Unit = println("Hello!") + |} + |""".stripMargin + ) + inputs.fromRoot { root => + val res = os.proc( + TestUtil.cli, + "--power", + "run", + "Hello.scala", + "--wasm", + "--wasm-runtime", + runtime, + extraOptions + ).call(cwd = root, check = false, mergeErrIntoOut = true) + expect(res.exitCode != 0) + expect(res.out.trim().contains("not yet supported")) + expect(res.out.trim().contains("scala-js/scala-js/issues/4991")) + } + } + + if (TestUtil.fromPath("deno").isDefined) + test("Run with --wasm-runtime deno") { + val inputs = TestInputs( + os.rel / "Hello.scala" -> + """object Hello { + | def main(args: Array[String]): Unit = println("Hello from Deno WASM!") + |} + |""".stripMargin + ) + inputs.fromRoot { root => + val output = os.proc( + TestUtil.cli, + "--power", + "run", + "Hello.scala", + "--wasm", + "--wasm-runtime", + "deno", + extraOptions + ).call(cwd = root).out.trim() + expect(output == "Hello from Deno WASM!") + } + } + + test("WASM multiple source files") { + val inputs = TestInputs( + os.rel / "Greeter.scala" -> + """trait Greeter { + | def greet(name: String): String + |} + | + |object EnthusiasticGreeter extends Greeter { + | def greet(name: String): String = s"Hello, $name!" + |} + |""".stripMargin, + os.rel / "Main.scala" -> + """object Main { + | def main(args: Array[String]): Unit = { + | println(EnthusiasticGreeter.greet("WASM")) + | } + |} + |""".stripMargin + ) + inputs.fromRoot { root => + val output = os.proc( + TestUtil.cli, + "--power", + "run", + "Main.scala", + "Greeter.scala", + "--wasm", + "--wasm-runtime", + "node", + extraOptions + ).call(cwd = root).out.trim() + expect(output == "Hello, WASM!") + } + } + + test("WASM exception handling") { + val inputs = TestInputs( + os.rel / "Hello.scala" -> + """object Hello { + | def riskyOp(x: Int): Int = + | if (x == 0) throw new IllegalArgumentException("zero!") + | else 100 / x + | + | def main(args: Array[String]): Unit = { + | val ok = try riskyOp(5).toString catch { case e: Exception => s"err: ${e.getMessage}" } + | val caught = try riskyOp(0).toString catch { case e: Exception => s"caught: ${e.getMessage}" } + | println(ok) + | println(caught) + | } + |} + |""".stripMargin + ) + inputs.fromRoot { root => + val output = os.proc( + TestUtil.cli, + "--power", + "run", + "Hello.scala", + "--wasm", + "--wasm-runtime", + "node", + extraOptions + ).call(cwd = root).out.trim() + val lines = output.linesIterator.toSeq + expect(lines.contains("20")) + expect(lines.contains("caught: zero!")) + } + } + + test("WASM collections and higher-order functions") { + val inputs = TestInputs( + os.rel / "Hello.scala" -> + """object Hello { + | def fib(n: Int): Int = if (n <= 1) n else fib(n - 1) + fib(n - 2) + | + | def main(args: Array[String]): Unit = { + | val fibs = (0 to 7).map(fib).toList + | println(fibs.mkString(", ")) + | println(fibs.filter(_ % 2 == 0).sum) + | println(fibs.foldLeft(0)(_ + _)) + | } + |} + |""".stripMargin + ) + inputs.fromRoot { root => + val output = os.proc( + TestUtil.cli, + "--power", + "run", + "Hello.scala", + "--wasm", + "--wasm-runtime", + "node", + extraOptions + ).call(cwd = root).out.trim() + val lines = output.linesIterator.toSeq + expect(lines.contains("0, 1, 1, 2, 3, 5, 8, 13")) + expect(lines.contains("10")) // 0 + 2 + 8 = 10 + expect(lines.contains("33")) // sum of first 8 fibs + } + } + + if (!actualScalaVersion.startsWith("2")) + test("WASM @main annotation (Scala 3)") { + // Scala.js always passes empty args to main, so @main with parameters won't work. + // Test @main without parameters instead. + val inputs = TestInputs( + os.rel / "Hello.scala" -> + """@main def hello(): Unit = + | println("Hello, Scala3!") + |""".stripMargin + ) + inputs.fromRoot { root => + val output = os.proc( + TestUtil.cli, + "--power", + "run", + "Hello.scala", + "--wasm", + "--wasm-runtime", + "node", + extraOptions + ).call(cwd = root).out.trim() + expect(output == "Hello, Scala3!") + } + } + test("remap imports directive") { val importmapFile = "importmap.json" val outDir = "out" diff --git a/modules/options/src/main/scala/scala/build/options/BuildOptions.scala b/modules/options/src/main/scala/scala/build/options/BuildOptions.scala index f0f09bf26b..9bc4a8b006 100644 --- a/modules/options/src/main/scala/scala/build/options/BuildOptions.scala +++ b/modules/options/src/main/scala/scala/build/options/BuildOptions.scala @@ -37,6 +37,7 @@ final case class BuildOptions( scalaOptions: ScalaOptions = ScalaOptions(), scalaJsOptions: ScalaJsOptions = ScalaJsOptions(), scalaNativeOptions: ScalaNativeOptions = ScalaNativeOptions(), + wasmOptions: WasmOptions = WasmOptions(), internalDependencies: InternalDependenciesOptions = InternalDependenciesOptions(), javaOptions: JavaOptions = JavaOptions(), jmhOptions: JmhOptions = JmhOptions(), diff --git a/modules/options/src/main/scala/scala/build/options/WasmOptions.scala b/modules/options/src/main/scala/scala/build/options/WasmOptions.scala new file mode 100644 index 0000000000..f96d697803 --- /dev/null +++ b/modules/options/src/main/scala/scala/build/options/WasmOptions.scala @@ -0,0 +1,26 @@ +package scala.build.options + +import scala.build.internal.Constants + +/** Options for WebAssembly compilation and execution. + * + * @param enabled + * If true, enable WASM output (Scala.js WASM backend) + * @param runtime + * The WASM runtime to use for execution (node, deno, wasmtime, wasmedge, wasmer) + * @param denoVersion + * Version of Deno to download (if not found on PATH) + */ +final case class WasmOptions( + enabled: Boolean = false, + runtime: WasmRuntime = WasmRuntime.default, + denoVersion: Option[String] = None +) { + def finalDenoVersion: String = + denoVersion.filter(_.nonEmpty).getOrElse(Constants.defaultDenoVersion) +} + +object WasmOptions { + implicit val hasHashData: HasHashData[WasmOptions] = HasHashData.derive + implicit val monoid: ConfigMonoid[WasmOptions] = ConfigMonoid.derive +} diff --git a/modules/options/src/main/scala/scala/build/options/WasmRuntime.scala b/modules/options/src/main/scala/scala/build/options/WasmRuntime.scala new file mode 100644 index 0000000000..f88f3028ab --- /dev/null +++ b/modules/options/src/main/scala/scala/build/options/WasmRuntime.scala @@ -0,0 +1,54 @@ +package scala.build.options + +import java.util.Locale + +/** Represents available WebAssembly runtimes for execution. + * + * JS-based runtimes (work now with Scala.js WASM backend): + * - Node: Uses Node.js (V8 engine) with JavaScript loader + * - Deno: Uses Deno (V8 engine) with ES module support + * + * Standalone runtimes (future, requires upstream Scala.js standalone WASM support): + * - Wasmtime: Primary standalone target, full WasmGC + Component Model + * - WasmEdge: Secondary standalone target, CNCF cloud-native runtime + * - Wasmer: Placeholder, no WasmGC support yet + */ +sealed abstract class WasmRuntime(val name: String) { + def isJsBased: Boolean = this match { + case WasmRuntime.Node | WasmRuntime.Deno => true + case _ => false + } + def isStandalone: Boolean = !isJsBased +} + +object WasmRuntime { + // JS-based runtimes (work now) + case object Node extends WasmRuntime("node") + case object Deno extends WasmRuntime("deno") + // Standalone runtimes (future - requires upstream Scala.js standalone WASM support) + case object Wasmtime extends WasmRuntime("wasmtime") + case object WasmEdge extends WasmRuntime("wasmedge") + case object Wasmer extends WasmRuntime("wasmer") + + val all: Seq[WasmRuntime] = Seq(Node, Deno, Wasmtime, WasmEdge, Wasmer) + + def default: WasmRuntime = Node + + def parse(s: String): Option[WasmRuntime] = + s.trim.toLowerCase(Locale.ROOT) match { + case "node" | "nodejs" => Some(Node) + case "deno" => Some(Deno) + case "wasmtime" => Some(Wasmtime) + case "wasmedge" => Some(WasmEdge) + case "wasmer" => Some(Wasmer) + case _ => None + } + + implicit val hashedType: HashedType[WasmRuntime] = runtime => runtime.name + + implicit val hasHashData: HasHashData[WasmRuntime] = HasHashData.asIs + + implicit val monoid: ConfigMonoid[WasmRuntime] = ConfigMonoid.instance[WasmRuntime](default) { + (a, b) => if (b == default) a else b + } +} diff --git a/website/docs/reference/cli-options.md b/website/docs/reference/cli-options.md index b817707754..75c6b31f75 100644 --- a/website/docs/reference/cli-options.md +++ b/website/docs/reference/cli-options.md @@ -1966,6 +1966,32 @@ A github token used to access GitHub. Not needed in most cases. Don't check for the newest available Scala CLI version upstream +## WebAssembly options + +Available in commands: + +[`run`](./commands.md#run), [`shebang`](./commands.md#shebang) + + + +### `--wasm` + +[Experimental] + +Enable WebAssembly output (Scala.js WASM backend). Uses Node.js by default. To show more options for WASM pass `--help-wasm` + +### `--wasm-runtime` + +[Experimental] + +WASM runtime to use: node (default), deno. Standalone runtimes (wasmtime, wasmedge) planned for future releases. + +### `--deno-version` + +[Experimental] + +Version of Deno to use. If Deno is not found on PATH, it will be downloaded automatically. + ## Watch options Available in commands: diff --git a/website/docs/reference/directives.md b/website/docs/reference/directives.md index d12254bca1..0e1894dde5 100644 --- a/website/docs/reference/directives.md +++ b/website/docs/reference/directives.md @@ -680,6 +680,27 @@ Add Scala.js options `//> using jsEmitWasm` +### WebAssembly + +Add WebAssembly options + +`//> using wasm` _true|false_ + +`//> using wasm` + +`//> using wasmRuntime` _node|deno|wasmtime|wasmedge|wasmer_ + +`//> using denoVersion` _value_ + +#### Examples +`//> using wasm` + +`//> using wasmRuntime node` + +`//> using wasmRuntime deno` + +`//> using denoVersion 2.1.4` + ### Test framework Set the test framework From b747949f0c0d3850af2551c4c924ff70432f3f75 Mon Sep 17 00:00:00 2001 From: lostflydev Date: Thu, 2 Apr 2026 08:44:21 +0500 Subject: [PATCH 2/8] Review fixes: remove runtime download and unsupported standalone runtimes - Move --wasm flag to dedicated Wasm help group with --help-wasm option - Simplify wasmOptions parsing with fold/toRight pattern - Add runtime validation with UnrecognizedWasmRuntimeError in directives - Auto-enable WASM when wasmRuntime directive is set - Update reference documentation Code style: simplify denoNeedsWasmFlag, explicit runtime match cases, clean type annotation, scalfmt --- build.mill | 2 - .../scala/scala/build/internal/Runner.scala | 16 +- .../scala/scala/cli/commands/run/Run.scala | 145 +++++++----------- .../commands/shared/HelpGroupOptions.scala | 9 +- .../cli/commands/shared/SharedOptions.scala | 26 +++- .../cli/commands/shared/WasmOptions.scala | 11 +- .../cli/internal/WasmRuntimeDownloader.scala | 104 ------------- .../errors/UnrecognizedWasmRuntimeError.scala | 4 + .../errors/UnsupportedWasmRuntimeError.scala | 3 - .../build/preprocessing/directives/Wasm.scala | 46 +++--- .../RunScalaJsTestDefinitions.scala | 26 ---- .../scala/build/options/WasmOptions.scala | 14 +- .../scala/build/options/WasmRuntime.scala | 23 +-- website/docs/reference/cli-options.md | 22 ++- website/docs/reference/commands.md | 30 ++-- website/docs/reference/directives.md | 40 +++-- .../reference/scala-command/cli-options.md | 18 +++ .../docs/reference/scala-command/commands.md | 18 +-- .../scala-command/runner-specification.md | 54 +++++++ 19 files changed, 247 insertions(+), 364 deletions(-) delete mode 100644 modules/cli/src/main/scala/scala/cli/internal/WasmRuntimeDownloader.scala create mode 100644 modules/core/src/main/scala/scala/build/errors/UnrecognizedWasmRuntimeError.scala delete mode 100644 modules/core/src/main/scala/scala/build/errors/UnsupportedWasmRuntimeError.scala diff --git a/build.mill b/build.mill index e67a2a754a..53e2c30df1 100644 --- a/build.mill +++ b/build.mill @@ -519,8 +519,6 @@ trait Core extends ScalaCliCrossSbtModule | def toolkitVersionForNative04 = "${Deps.toolkitVersionForNative04}" | def toolkitVersionForNative05 = "${Deps.toolkitVersionForNative05}" | - | def defaultDenoVersion = "2.1.4" - | | def typelevelOrganization = "${Deps.typelevelToolkit.dep.module.organization.value}" | def typelevelToolkitDefaultVersion = "${Deps.typelevelToolkitVersion}" | def typelevelToolkitMaxScalaNative = "${Deps.Versions.maxScalaNativeForTypelevelToolkit}" diff --git a/modules/build/src/main/scala/scala/build/internal/Runner.scala b/modules/build/src/main/scala/scala/build/internal/Runner.scala index 4ba52d017b..dc8e274fa6 100644 --- a/modules/build/src/main/scala/scala/build/internal/Runner.scala +++ b/modules/build/src/main/scala/scala/build/internal/Runner.scala @@ -238,10 +238,7 @@ object Runner { // Deno 2.x+ bundles V8 13+ which has wasm-exnref enabled by default; no flag needed. private def denoNeedsWasmFlag: Boolean = - denoMajorVersion.flatMap { major => - if (major >= 2) Some(false) // Deno 2.x+ has V8 13+ with wasm-exnref by default - else Some(true) - }.getOrElse(true) // true if unknown + denoMajorVersion.forall(_ < 2) // true if unknown or < 2 private def endsWithCaseInsensitive(s: String, suffix: String): Boolean = s.length >= suffix.length && @@ -380,10 +377,9 @@ object Runner { def denoCommand( entrypoint: File, - args: Seq[String], - denoPathOpt: Option[String] = None + args: Seq[String] ): Seq[String] = { - val denoPath = denoPathOpt.getOrElse(findInPath("deno").fold("deno")(_.toString)) + val denoPath = findInPath("deno").fold("deno")(_.toString) val denoFlags = Seq("run", "--allow-read") Seq(denoPath) ++ denoFlags ++ Seq(entrypoint.getAbsolutePath) ++ args } @@ -393,14 +389,12 @@ object Runner { args: Seq[String], logger: Logger, allowExecve: Boolean = false, - emitWasm: Boolean = false, - denoPathOpt: Option[String] = None + emitWasm: Boolean = false ): Either[BuildException, Process] = either { - val denoPath: String = denoPathOpt.getOrElse { + val denoPath: String = value(findInPath("deno") .map(_.toString) .toRight(DenoNotFoundError())) - } val denoFlags = Seq("run", "--allow-read") val extraEnv = if (emitWasm && denoNeedsWasmFlag) Map("DENO_V8_FLAGS" -> "--experimental-wasm-exnref") diff --git a/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala b/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala index af484d123d..c8253ee14e 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala @@ -12,7 +12,7 @@ import java.util.concurrent.atomic.AtomicReference import scala.build.* import scala.build.EitherCps.{either, value} import scala.build.Ops.* -import scala.build.errors.{BuildException, CompositeBuildException, UnsupportedWasmRuntimeError} +import scala.build.errors.{BuildException, CompositeBuildException} import scala.build.input.* import scala.build.internal.{Constants, Runner, ScalaJsLinkerConfig} import scala.build.internals.ConsoleUtils.ScalaCliConsole @@ -28,7 +28,7 @@ import scala.cli.commands.util.BuildCommandHelpers.* import scala.cli.commands.util.{BuildCommandHelpers, RunHadoop, RunSpark} import scala.cli.commands.{CommandUtils, ScalaCommand, SpecificationLevel, WatchUtil} import scala.cli.config.Keys -import scala.cli.internal.{ProcUtil, WasmRuntimeDownloader} +import scala.cli.internal.ProcUtil import scala.cli.packaging.Library.fullClassPathMaybeAsJar import scala.cli.util.ArgHelpers.* import scala.cli.util.ConfigDbUtils @@ -478,101 +478,66 @@ object Run extends ScalaCommand[RunOptions] with BuildCommandHelpers { // Check if WASM mode is requested if wasmOpts.enabled then { - val runtime = wasmOpts.runtime - - if runtime.isJsBased then { - // JS-based WASM path - uses Scala.js WASM with JavaScript helpers (Node.js or Deno) - val esModule = true // WASM backend uses ES modules - scratchDirOpt.foreach(os.makeDir.all(_)) - val jsDest = os.temp( - dir = scratchDirOpt.orNull, - prefix = "main", - suffix = ".mjs", - deleteOnExit = scratchDirOpt.isEmpty - ) - - // Resolve Deno binary: check PATH first, download if needed - val denoPathOpt: Option[String] = runtime match { - case WasmRuntime.Deno => - val denoCmd = value(WasmRuntimeDownloader.denoCommand( - wasmOpts.finalDenoVersion, - build.options.archiveCache, - logger - )) - Some(denoCmd.head) - case _ => None - } + val runtime = wasmOpts.runtime + val esModule = true // WASM backend uses ES modules + scratchDirOpt.foreach(os.makeDir.all(_)) + val jsDest = os.temp( + dir = scratchDirOpt.orNull, + prefix = "main", + suffix = ".mjs", + deleteOnExit = scratchDirOpt.isEmpty + ) - val linkerConfig = build.options.scalaJsOptions.linkerConfig(logger) - .copy(emitWasm = true, moduleKind = ScalaJsLinkerConfig.ModuleKind.ESModule) - - val res = Package.linkJs( - builds = builds, - dest = jsDest, - mainClassOpt = Some(mainClass), - addTestInitializer = false, - config = linkerConfig, - fullOpt = value(build.options.scalaJsOptions.fullOpt), - noOpt = build.options.scalaJsOptions.noOpt.getOrElse(false), - logger = logger, - scratchDirOpt = scratchDirOpt - ).map { outputPath => - if showCommand then + val linkerConfig = build.options.scalaJsOptions.linkerConfig(logger) + .copy(emitWasm = true, moduleKind = ScalaJsLinkerConfig.ModuleKind.ESModule) + + val res = Package.linkJs( + builds = builds, + dest = jsDest, + mainClassOpt = Some(mainClass), + addTestInitializer = false, + config = linkerConfig, + fullOpt = value(build.options.scalaJsOptions.fullOpt), + noOpt = build.options.scalaJsOptions.noOpt.getOrElse(false), + logger = logger, + scratchDirOpt = scratchDirOpt + ).map { outputPath => + if showCommand then + runtime match { + case WasmRuntime.Deno => + Left(Runner.denoCommand(outputPath.toIO, args)) + case WasmRuntime.Node => + Left(Runner.jsCommand(outputPath.toIO, args, jsDom = false, emitWasm = true)) + } + else { + val process = value { runtime match { case WasmRuntime.Deno => - Left(Runner.denoCommand(outputPath.toIO, args, denoPathOpt = denoPathOpt)) - case _ => - Left(Runner.jsCommand(outputPath.toIO, args, jsDom = false, emitWasm = true)) - } - else { - val process = value { - runtime match { - case WasmRuntime.Deno => - Runner.runDeno( - outputPath.toIO, - args, - logger, - allowExecve = effectiveAllowExecve, - emitWasm = true, - denoPathOpt = denoPathOpt - ) - case _ => - Runner.runJs( - outputPath.toIO, - args, - logger, - allowExecve = effectiveAllowExecve, - jsDom = false, - sourceMap = build.options.scalaJsOptions.emitSourceMaps, - esModule = esModule, - emitWasm = true - ) - } + Runner.runDeno( + outputPath.toIO, + args, + logger, + allowExecve = effectiveAllowExecve, + emitWasm = true + ) + case WasmRuntime.Node => + Runner.runJs( + outputPath.toIO, + args, + logger, + allowExecve = effectiveAllowExecve, + jsDom = false, + sourceMap = build.options.scalaJsOptions.emitSourceMaps, + esModule = esModule, + emitWasm = true + ) } - process.onExit().thenApply(_ => if os.exists(jsDest) then os.remove(jsDest)) - Right((process, None)) } + process.onExit().thenApply(_ => if os.exists(jsDest) then os.remove(jsDest)) + Right((process, None)) } - value(res) - } - else { - // Standalone WASM runtimes - not yet supported. - // Scala.js currently produces JS-dependent WASM output. - // Standalone support requires upstream Scala.js changes (scala-js/scala-js#4991). - val runtimeName = runtime.name - val extraNote = runtime match { - case WasmRuntime.Wasmer => - " Note: Wasmer does not yet support WasmGC, which is required for Scala WASM output." - case _ => "" - } - value(Left(new UnsupportedWasmRuntimeError( - s"Standalone WASM runtime '$runtimeName' is not yet supported." + - s"$extraNote" + - " Scala.js currently produces JavaScript-dependent WASM output." + - " Standalone WASM support is tracked at: https://github.com/scala-js/scala-js/issues/4991" + - " Use --wasm-runtime node (default) or --wasm-runtime deno for JS-based WASM execution." - ))) } + value(res) } else build.options.platform.value match { diff --git a/modules/cli/src/main/scala/scala/cli/commands/shared/HelpGroupOptions.scala b/modules/cli/src/main/scala/scala/cli/commands/shared/HelpGroupOptions.scala index ef012e22f0..76d78dcb19 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/shared/HelpGroupOptions.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/shared/HelpGroupOptions.scala @@ -49,7 +49,13 @@ case class HelpGroupOptions( @Name("fmtHelp") @Tag(tags.implementation) @Tag(tags.inShortHelp) - helpScalafmt: Boolean = false + helpScalafmt: Boolean = false, + @Group(HelpGroup.Help.toString) + @HelpMessage("Show options for WebAssembly") + @Name("wasmHelp") + @Tag(tags.implementation) + @Tag(tags.inShortHelp) + helpWasm: Boolean = false ) { private def printHelpWithGroup(help: Help[?], helpFormat: HelpFormat, group: String): Nothing = { @@ -68,6 +74,7 @@ case class HelpGroupOptions( def maybePrintGroupHelp(help: Help[?], helpFormat: HelpFormat): Unit = { if (helpJs) printHelpWithGroup(help, helpFormat, HelpGroup.ScalaJs.toString) else if (helpNative) printHelpWithGroup(help, helpFormat, HelpGroup.ScalaNative.toString) + else if (helpWasm) printHelpWithGroup(help, helpFormat, HelpGroup.Wasm.toString) } } diff --git a/modules/cli/src/main/scala/scala/cli/commands/shared/SharedOptions.scala b/modules/cli/src/main/scala/scala/cli/commands/shared/SharedOptions.scala index c48dbc43bd..9c988b6dca 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/shared/SharedOptions.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/shared/SharedOptions.scala @@ -313,13 +313,23 @@ final case class SharedOptions( ) } - private def buildWasmOptions(opts: WasmOptions): options.WasmOptions = { + private def buildWasmOptions( + opts: WasmOptions + ): Either[BuildException, options.WasmOptions] = { import opts._ - options.WasmOptions( - enabled = wasm, - runtime = - wasmRuntime.flatMap(options.WasmRuntime.parse).getOrElse(options.WasmRuntime.default), - denoVersion = denoVersion + val wasmEnabled = wasm || wasmRuntime.isDefined + val parsedRuntime: Either[BuildException, options.WasmRuntime] = + wasmRuntime.fold(Right(options.WasmRuntime.default)) { rt => + options.WasmRuntime.parse(rt).toRight { + val validValues = options.WasmRuntime.all.map(_.name).mkString(", ") + new scala.build.errors.UnrecognizedWasmRuntimeError(rt, validValues) + } + } + parsedRuntime.map(runtime => + options.WasmOptions( + enabled = wasmEnabled, + runtime = runtime + ) ) } @@ -348,7 +358,7 @@ final case class SharedOptions( } val parsedPlatform = platform.map(Platform.normalize).flatMap(Platform.parse) // WASM mode requires Scala.js platform for compilation - val wasmEnabled = wasmOptions.wasm + val wasmEnabled = wasmOptions.wasm || wasmOptions.wasmRuntime.isDefined val platformOpt = value { (parsedPlatform, js.js, native.native, wasmEnabled) match { case (Some(p: Platform.JS.type), _, false, _) => Right(Some(p)) @@ -454,7 +464,7 @@ final case class SharedOptions( ), scalaJsOptions = scalaJsOptions(js), scalaNativeOptions = snOpts, - wasmOptions = buildWasmOptions(wasmOptions), + wasmOptions = value(buildWasmOptions(wasmOptions)), javaOptions = value(scala.cli.commands.util.JvmUtils.javaOptions(jvm)), jmhOptions = scala.build.options.JmhOptions( jmhVersion = benchmarking.jmhVersion, diff --git a/modules/cli/src/main/scala/scala/cli/commands/shared/WasmOptions.scala b/modules/cli/src/main/scala/scala/cli/commands/shared/WasmOptions.scala index d8793afaa2..a2e6251fdc 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/shared/WasmOptions.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/shared/WasmOptions.scala @@ -8,20 +8,15 @@ import scala.cli.commands.tags // format: off final case class WasmOptions( - @Group(HelpGroup.Scala.toString) + @Group(HelpGroup.Wasm.toString) @Tag(tags.experimental) @HelpMessage("Enable WebAssembly output (Scala.js WASM backend). Uses Node.js by default. To show more options for WASM pass `--help-wasm`") wasm: Boolean = false, @Group(HelpGroup.Wasm.toString) @Tag(tags.experimental) - @HelpMessage("WASM runtime to use: node (default), deno. Standalone runtimes (wasmtime, wasmedge) planned for future releases.") - wasmRuntime: Option[String] = None, - - @Group(HelpGroup.Wasm.toString) - @Tag(tags.experimental) - @HelpMessage("Version of Deno to use. If Deno is not found on PATH, it will be downloaded automatically.") - denoVersion: Option[String] = None + @HelpMessage("WASM runtime to use: node (default), deno") + wasmRuntime: Option[String] = None ) // format: on diff --git a/modules/cli/src/main/scala/scala/cli/internal/WasmRuntimeDownloader.scala b/modules/cli/src/main/scala/scala/cli/internal/WasmRuntimeDownloader.scala deleted file mode 100644 index 751e087034..0000000000 --- a/modules/cli/src/main/scala/scala/cli/internal/WasmRuntimeDownloader.scala +++ /dev/null @@ -1,104 +0,0 @@ -package scala.cli.internal - -import coursier.cache.ArchiveCache -import coursier.util.Task - -import java.util.Locale - -import scala.build.EitherCps.{either, value} -import scala.build.Logger -import scala.build.errors.BuildException -import scala.build.internal.FetchExternalBinary -import scala.util.Properties - -/** Resolves Deno binary for WASM execution. - * - * Deno is first looked up on the system PATH. If not found, it is downloaded from GitHub releases - * and cached via Coursier's ArchiveCache. - */ -object WasmRuntimeDownloader { - - /** Returns the command to run Deno. - * - * First checks system PATH, otherwise downloads the binary. - */ - def denoCommand( - version: String, - archiveCache: ArchiveCache[Task], - logger: Logger - ): Either[BuildException, Seq[String]] = either { - findOnPath("deno") match { - case Some(path) => - logger.debug(s"Using system deno at: $path") - Seq(path) - case None => - logger.message(s"Deno not found on PATH, downloading v$version...") - val binary = value(fetchDeno(version, archiveCache, logger)) - Seq(binary.toString) - } - } - - /** Find an executable on the system PATH */ - private def findOnPath(name: String): Option[String] = { - val exeName = if (Properties.isWin) s"$name.exe" else name - sys.env.get("PATH").flatMap { pathEnv => - pathEnv.split(java.io.File.pathSeparator).view.map { dir => - val file = new java.io.File(dir, exeName) - if (file.exists() && file.canExecute) Some(file.getAbsolutePath) - else None - }.find(_.isDefined).flatten - } - } - - private def detectOs(win: String, linux: String, mac: String): Either[BuildException, String] = - if (Properties.isWin) Right(win) - else if (Properties.isLinux) Right(linux) - else if (Properties.isMac) Right(mac) - else Left(new WasmRuntimeDownloadError(s"Unsupported OS: ${sys.props("os.name")}")) - - private def detectArch64(x86_64: String, aarch64: String): Either[BuildException, String] = - sys.props("os.arch").toLowerCase(Locale.ROOT) match { - case "amd64" | "x86_64" => Right(x86_64) - case "aarch64" | "arm64" => Right(aarch64) - case other => Left(new WasmRuntimeDownloadError(s"Unsupported architecture: $other")) - } - - /** Fetches Deno binary for the current platform. - * - * Deno releases are at: - * https://github.com/denoland/deno/releases/download/v{version}/deno-{platform}.zip - */ - private def fetchDeno( - version: String, - archiveCache: ArchiveCache[Task], - logger: Logger - ): Either[BuildException, os.Path] = either { - val platform = value(denoPlatform) - val url = s"https://github.com/denoland/deno/releases/download/v$version/deno-$platform.zip" - - val binaryOpt = value { - FetchExternalBinary.fetchLauncher( - url = url, - changing = false, - archiveCache = archiveCache, - logger = logger, - launcherPrefix = "deno", - launcherPathOpt = None, - makeExecutable = true - ) - } - - binaryOpt.getOrElse { - value(Left(new WasmRuntimeDownloadError(s"Could not download Deno v$version for $platform"))) - } - } - - /** Platform suffix for Deno downloads */ - private def denoPlatform: Either[BuildException, String] = either { - val arch = value(detectArch64("x86_64", "aarch64")) - val os = value(detectOs("pc-windows-msvc", "unknown-linux-gnu", "apple-darwin")) - s"$arch-$os" - } -} - -class WasmRuntimeDownloadError(message: String) extends BuildException(message) diff --git a/modules/core/src/main/scala/scala/build/errors/UnrecognizedWasmRuntimeError.scala b/modules/core/src/main/scala/scala/build/errors/UnrecognizedWasmRuntimeError.scala new file mode 100644 index 0000000000..46e2f43b6c --- /dev/null +++ b/modules/core/src/main/scala/scala/build/errors/UnrecognizedWasmRuntimeError.scala @@ -0,0 +1,4 @@ +package scala.build.errors + +class UnrecognizedWasmRuntimeError(runtime: String, validValues: String) + extends BuildException(s"Unrecognized WASM runtime: '$runtime'. Valid values: $validValues") diff --git a/modules/core/src/main/scala/scala/build/errors/UnsupportedWasmRuntimeError.scala b/modules/core/src/main/scala/scala/build/errors/UnsupportedWasmRuntimeError.scala deleted file mode 100644 index b663b6a956..0000000000 --- a/modules/core/src/main/scala/scala/build/errors/UnsupportedWasmRuntimeError.scala +++ /dev/null @@ -1,3 +0,0 @@ -package scala.build.errors - -final class UnsupportedWasmRuntimeError(message: String) extends BuildException(message) diff --git a/modules/directives/src/main/scala/scala/build/preprocessing/directives/Wasm.scala b/modules/directives/src/main/scala/scala/build/preprocessing/directives/Wasm.scala index 361fcc32ab..9a1b7f67f9 100644 --- a/modules/directives/src/main/scala/scala/build/preprocessing/directives/Wasm.scala +++ b/modules/directives/src/main/scala/scala/build/preprocessing/directives/Wasm.scala @@ -2,7 +2,7 @@ package scala.build.preprocessing.directives import scala.build.Positioned import scala.build.directives.* -import scala.build.errors.BuildException +import scala.build.errors.{BuildException, UnrecognizedWasmRuntimeError} import scala.build.options.{BuildOptions, Platform, ScalaOptions, WasmOptions, WasmRuntime} import scala.cli.commands.SpecificationLevel @@ -10,40 +10,44 @@ import scala.cli.commands.SpecificationLevel @DirectiveExamples("//> using wasm") @DirectiveExamples("//> using wasmRuntime node") @DirectiveExamples("//> using wasmRuntime deno") -@DirectiveExamples("//> using denoVersion 2.1.4") @DirectiveUsage( - "//> using wasm|wasmRuntime|denoVersion _value_", + "//> using wasm|wasmRuntime _value_", """ |`//> using wasm` _true|false_ | |`//> using wasm` | - |`//> using wasmRuntime` _node|deno|wasmtime|wasmedge|wasmer_ - | - |`//> using denoVersion` _value_ + |`//> using wasmRuntime` _node|deno_ |""".stripMargin ) @DirectiveDescription("Add WebAssembly options") @DirectiveLevel(SpecificationLevel.EXPERIMENTAL) final case class Wasm( wasm: Option[Boolean] = None, - wasmRuntime: Option[String] = None, - denoVersion: Option[String] = None + wasmRuntime: Option[String] = None ) extends HasBuildOptions { def buildOptions: Either[BuildException, BuildOptions] = { - val parsedRuntime = wasmRuntime.flatMap(WasmRuntime.parse) - val wasmOptions = WasmOptions( - enabled = wasm.getOrElse(false), - runtime = parsedRuntime.getOrElse(WasmRuntime.default), - denoVersion = denoVersion - ) - // When WASM is enabled, force Platform.JS (Scala.js WASM backend requires JS compilation) - val scalaOptions = - if (wasm.getOrElse(false)) - ScalaOptions(platform = Some(Positioned.none(Platform.JS))) - else - ScalaOptions() - Right(BuildOptions(scalaOptions = scalaOptions, wasmOptions = wasmOptions)) + val parsedRuntime = + wasmRuntime.fold(Right(WasmRuntime.default): Either[BuildException, WasmRuntime]) { rt => + WasmRuntime.parse(rt).toRight { + val validValues = WasmRuntime.all.map(_.name).mkString(", ") + new UnrecognizedWasmRuntimeError(rt, validValues) + } + } + parsedRuntime.map { runtime => + val wasmEnabled = wasm.getOrElse(false) || wasmRuntime.isDefined + val wasmOptions = WasmOptions( + enabled = wasmEnabled, + runtime = runtime + ) + // When WASM is enabled, force Platform.JS (Scala.js WASM backend requires JS compilation) + val scalaOptions = + if (wasmEnabled) + ScalaOptions(platform = Some(Positioned.none(Platform.JS))) + else + ScalaOptions() + BuildOptions(scalaOptions = scalaOptions, wasmOptions = wasmOptions) + } } } diff --git a/modules/integration/src/test/scala/scala/cli/integration/RunScalaJsTestDefinitions.scala b/modules/integration/src/test/scala/scala/cli/integration/RunScalaJsTestDefinitions.scala index 8436bc2e0f..7ff3972f7a 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/RunScalaJsTestDefinitions.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/RunScalaJsTestDefinitions.scala @@ -428,32 +428,6 @@ trait RunScalaJsTestDefinitions { this: RunTestDefinitions => } } - for (runtime <- Seq("wasmtime", "wasmedge", "wasmer")) - test(s"Unsupported WASM runtime '$runtime' gives clear error") { - val inputs = TestInputs( - os.rel / "Hello.scala" -> - """object Hello { - | def main(args: Array[String]): Unit = println("Hello!") - |} - |""".stripMargin - ) - inputs.fromRoot { root => - val res = os.proc( - TestUtil.cli, - "--power", - "run", - "Hello.scala", - "--wasm", - "--wasm-runtime", - runtime, - extraOptions - ).call(cwd = root, check = false, mergeErrIntoOut = true) - expect(res.exitCode != 0) - expect(res.out.trim().contains("not yet supported")) - expect(res.out.trim().contains("scala-js/scala-js/issues/4991")) - } - } - if (TestUtil.fromPath("deno").isDefined) test("Run with --wasm-runtime deno") { val inputs = TestInputs( diff --git a/modules/options/src/main/scala/scala/build/options/WasmOptions.scala b/modules/options/src/main/scala/scala/build/options/WasmOptions.scala index f96d697803..34450e2385 100644 --- a/modules/options/src/main/scala/scala/build/options/WasmOptions.scala +++ b/modules/options/src/main/scala/scala/build/options/WasmOptions.scala @@ -1,24 +1,16 @@ package scala.build.options -import scala.build.internal.Constants - /** Options for WebAssembly compilation and execution. * * @param enabled * If true, enable WASM output (Scala.js WASM backend) * @param runtime - * The WASM runtime to use for execution (node, deno, wasmtime, wasmedge, wasmer) - * @param denoVersion - * Version of Deno to download (if not found on PATH) + * The WASM runtime to use for execution (node, deno) */ final case class WasmOptions( enabled: Boolean = false, - runtime: WasmRuntime = WasmRuntime.default, - denoVersion: Option[String] = None -) { - def finalDenoVersion: String = - denoVersion.filter(_.nonEmpty).getOrElse(Constants.defaultDenoVersion) -} + runtime: WasmRuntime = WasmRuntime.default +) object WasmOptions { implicit val hasHashData: HasHashData[WasmOptions] = HasHashData.derive diff --git a/modules/options/src/main/scala/scala/build/options/WasmRuntime.scala b/modules/options/src/main/scala/scala/build/options/WasmRuntime.scala index f88f3028ab..a2e68d63f8 100644 --- a/modules/options/src/main/scala/scala/build/options/WasmRuntime.scala +++ b/modules/options/src/main/scala/scala/build/options/WasmRuntime.scala @@ -7,30 +7,14 @@ import java.util.Locale * JS-based runtimes (work now with Scala.js WASM backend): * - Node: Uses Node.js (V8 engine) with JavaScript loader * - Deno: Uses Deno (V8 engine) with ES module support - * - * Standalone runtimes (future, requires upstream Scala.js standalone WASM support): - * - Wasmtime: Primary standalone target, full WasmGC + Component Model - * - WasmEdge: Secondary standalone target, CNCF cloud-native runtime - * - Wasmer: Placeholder, no WasmGC support yet */ -sealed abstract class WasmRuntime(val name: String) { - def isJsBased: Boolean = this match { - case WasmRuntime.Node | WasmRuntime.Deno => true - case _ => false - } - def isStandalone: Boolean = !isJsBased -} +sealed abstract class WasmRuntime(val name: String) object WasmRuntime { - // JS-based runtimes (work now) case object Node extends WasmRuntime("node") case object Deno extends WasmRuntime("deno") - // Standalone runtimes (future - requires upstream Scala.js standalone WASM support) - case object Wasmtime extends WasmRuntime("wasmtime") - case object WasmEdge extends WasmRuntime("wasmedge") - case object Wasmer extends WasmRuntime("wasmer") - val all: Seq[WasmRuntime] = Seq(Node, Deno, Wasmtime, WasmEdge, Wasmer) + val all: Seq[WasmRuntime] = Seq(Node, Deno) def default: WasmRuntime = Node @@ -38,9 +22,6 @@ object WasmRuntime { s.trim.toLowerCase(Locale.ROOT) match { case "node" | "nodejs" => Some(Node) case "deno" => Some(Deno) - case "wasmtime" => Some(Wasmtime) - case "wasmedge" => Some(WasmEdge) - case "wasmer" => Some(Wasmer) case _ => None } diff --git a/website/docs/reference/cli-options.md b/website/docs/reference/cli-options.md index 75c6b31f75..4ea7797d64 100644 --- a/website/docs/reference/cli-options.md +++ b/website/docs/reference/cli-options.md @@ -591,6 +591,12 @@ Aliases: `--fmt-help`, `--help-fmt`, `--scalafmt-help` Show options for Scalafmt +### `--help-wasm` + +Aliases: `--wasm-help` + +Show options for WebAssembly + ## Install completions options Available in commands: @@ -1966,31 +1972,21 @@ A github token used to access GitHub. Not needed in most cases. Don't check for the newest available Scala CLI version upstream -## WebAssembly options +## Wasm options Available in commands: -[`run`](./commands.md#run), [`shebang`](./commands.md#shebang) +[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) ### `--wasm` -[Experimental] - Enable WebAssembly output (Scala.js WASM backend). Uses Node.js by default. To show more options for WASM pass `--help-wasm` ### `--wasm-runtime` -[Experimental] - -WASM runtime to use: node (default), deno. Standalone runtimes (wasmtime, wasmedge) planned for future releases. - -### `--deno-version` - -[Experimental] - -Version of Deno to use. If Deno is not found on PATH, it will be downloaded automatically. +WASM runtime to use: node (default), deno ## Watch options diff --git a/website/docs/reference/commands.md b/website/docs/reference/commands.md index 9aaeff82ed..643f0cd72e 100644 --- a/website/docs/reference/commands.md +++ b/website/docs/reference/commands.md @@ -32,7 +32,7 @@ All supported types of inputs can be mixed with each other. For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/compile -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [compile](./cli-options.md#compile-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [compile](./cli-options.md#compile-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ## config @@ -83,7 +83,7 @@ Accepts option groups: [config](./cli-options.md#config-options), [coursier](./c Update dependency directives in the project -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [dependency update](./cli-options.md#dependency-update-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [dependency update](./cli-options.md#dependency-update-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [workspace](./cli-options.md#workspace-options) ## doc @@ -97,7 +97,7 @@ All supported types of inputs can be mixed with each other. For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/doc -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [doc](./cli-options.md#doc-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [doc](./cli-options.md#doc-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [workspace](./cli-options.md#workspace-options) ## export @@ -119,7 +119,7 @@ The `export` sub-command is experimental. Please bear in mind that non-ideal user experience should be expected. If you encounter any bugs or have feedback to share, make sure to reach out to the maintenance team at https://github.com/VirtusLab/scala-cli -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [export](./cli-options.md#export-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [export](./cli-options.md#export-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [workspace](./cli-options.md#workspace-options) ## fix @@ -145,7 +145,7 @@ The `fix` sub-command is experimental. Please bear in mind that non-ideal user experience should be expected. If you encounter any bugs or have feedback to share, make sure to reach out to the maintenance team at https://github.com/VirtusLab/scala-cli -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [fix](./cli-options.md#fix-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [Scalafix](./cli-options.md#scalafix-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [fix](./cli-options.md#fix-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [Scalafix](./cli-options.md#scalafix-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [workspace](./cli-options.md#workspace-options) ## fmt @@ -162,7 +162,7 @@ All standard Scala CLI inputs are accepted, but only Scala sources will be forma For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/fmt -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [fmt](./cli-options.md#fmt-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [fmt](./cli-options.md#fmt-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [workspace](./cli-options.md#workspace-options) ## help @@ -214,7 +214,7 @@ All supported types of inputs can be mixed with each other. For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/repl -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [repl](./cli-options.md#repl-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [repl](./cli-options.md#repl-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ## package @@ -232,7 +232,7 @@ All supported types of inputs can be mixed with each other. For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/package -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [package](./cli-options.md#package-options), [packager](./cli-options.md#packager-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [package](./cli-options.md#package-options), [packager](./cli-options.md#packager-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ## publish @@ -259,7 +259,7 @@ The `publish` sub-command is experimental. Please bear in mind that non-ideal user experience should be expected. If you encounter any bugs or have feedback to share, make sure to reach out to the maintenance team at https://github.com/VirtusLab/scala-cli -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [pgp scala signing](./cli-options.md#pgp-scala-signing-options), [power](./cli-options.md#power-options), [publish](./cli-options.md#publish-options), [publish connection](./cli-options.md#publish-connection-options), [publish params](./cli-options.md#publish-params-options), [publish repository](./cli-options.md#publish-repository-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [pgp scala signing](./cli-options.md#pgp-scala-signing-options), [power](./cli-options.md#power-options), [publish](./cli-options.md#publish-options), [publish connection](./cli-options.md#publish-connection-options), [publish params](./cli-options.md#publish-params-options), [publish repository](./cli-options.md#publish-repository-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ## publish local @@ -271,7 +271,7 @@ The `publish-local` sub-command is experimental. Please bear in mind that non-ideal user experience should be expected. If you encounter any bugs or have feedback to share, make sure to reach out to the maintenance team at https://github.com/VirtusLab/scala-cli -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [pgp scala signing](./cli-options.md#pgp-scala-signing-options), [power](./cli-options.md#power-options), [publish](./cli-options.md#publish-options), [publish local](./cli-options.md#publish-local-options), [publish params](./cli-options.md#publish-params-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [pgp scala signing](./cli-options.md#pgp-scala-signing-options), [power](./cli-options.md#power-options), [publish](./cli-options.md#publish-options), [publish local](./cli-options.md#publish-local-options), [publish params](./cli-options.md#publish-params-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ## publish setup @@ -309,7 +309,7 @@ To pass arguments to the actual application, just add them after `--`, like: For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/run -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [run](./cli-options.md#run-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [run](./cli-options.md#run-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ## github secret create @@ -356,7 +356,7 @@ Using directives can be defined in all supported input source file types. For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/setup-ide -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [bsp file](./cli-options.md#bsp-file-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [setup IDE](./cli-options.md#setup-ide-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [bsp file](./cli-options.md#bsp-file-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [setup IDE](./cli-options.md#setup-ide-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [workspace](./cli-options.md#workspace-options) ## shebang @@ -387,7 +387,7 @@ Using this, it is possible to conveniently set up Unix shebang scripts. For exam For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/shebang -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [run](./cli-options.md#run-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [run](./cli-options.md#run-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ## test @@ -411,7 +411,7 @@ All supported types of inputs can be mixed with each other. For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/test -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [test](./cli-options.md#test-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [test](./cli-options.md#test-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ## uninstall @@ -514,7 +514,7 @@ It is normally supposed to be invoked by your IDE when a Scala CLI project is im Detailed documentation can be found on our website: https://scala-cli.virtuslab.org -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [bsp](./cli-options.md#bsp-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [bsp](./cli-options.md#bsp-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [workspace](./cli-options.md#workspace-options) ### default-file diff --git a/website/docs/reference/directives.md b/website/docs/reference/directives.md index 0e1894dde5..cf75f0cbaf 100644 --- a/website/docs/reference/directives.md +++ b/website/docs/reference/directives.md @@ -680,27 +680,6 @@ Add Scala.js options `//> using jsEmitWasm` -### WebAssembly - -Add WebAssembly options - -`//> using wasm` _true|false_ - -`//> using wasm` - -`//> using wasmRuntime` _node|deno|wasmtime|wasmedge|wasmer_ - -`//> using denoVersion` _value_ - -#### Examples -`//> using wasm` - -`//> using wasmRuntime node` - -`//> using wasmRuntime deno` - -`//> using denoVersion 2.1.4` - ### Test framework Set the test framework @@ -728,6 +707,25 @@ Use a toolkit as dependency (not supported in Scala 2.12), 'default' version for `//> using test.toolkit default` +### WASM options + +Add WebAssembly options + + +`//> using wasm` _true|false_ + +`//> using wasm` + +`//> using wasmRuntime` _node|deno_ + + +#### Examples +`//> using wasm` + +`//> using wasmRuntime node` + +`//> using wasmRuntime deno` + ### Watch additional inputs Watch additional files or directories when using watch mode diff --git a/website/docs/reference/scala-command/cli-options.md b/website/docs/reference/scala-command/cli-options.md index 74cba5642f..bd8ebaf16a 100644 --- a/website/docs/reference/scala-command/cli-options.md +++ b/website/docs/reference/scala-command/cli-options.md @@ -498,6 +498,14 @@ Aliases: `--fmt-help`, `--help-fmt`, `--scalafmt-help` Show options for Scalafmt +### `--help-wasm` + +Aliases: `--wasm-help` + +`IMPLEMENTATION specific` per Scala Runner specification + +Show options for WebAssembly + ## Install completions options Available in commands: @@ -1487,6 +1495,16 @@ A github token used to access GitHub. Not needed in most cases. Don't check for the newest available Scala CLI version upstream +## Wasm options + +Available in commands: + +[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`doc`](./commands.md#doc), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) + + + +*This section was automatically generated and may be empty if no options were available.* + ## Watch options Available in commands: diff --git a/website/docs/reference/scala-command/commands.md b/website/docs/reference/scala-command/commands.md index 8b7c42a9eb..e7fbd71e5a 100644 --- a/website/docs/reference/scala-command/commands.md +++ b/website/docs/reference/scala-command/commands.md @@ -31,7 +31,7 @@ All supported types of inputs can be mixed with each other. For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/compile -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [compile](./cli-options.md#compile-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [compile](./cli-options.md#compile-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ### config @@ -90,7 +90,7 @@ All supported types of inputs can be mixed with each other. For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/doc -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [doc](./cli-options.md#doc-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [doc](./cli-options.md#doc-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [workspace](./cli-options.md#workspace-options) ### repl @@ -112,7 +112,7 @@ All supported types of inputs can be mixed with each other. For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/repl -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [repl](./cli-options.md#repl-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [repl](./cli-options.md#repl-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ### run @@ -138,7 +138,7 @@ To pass arguments to the actual application, just add them after `--`, like: For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/run -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [run](./cli-options.md#run-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [run](./cli-options.md#run-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ### shebang @@ -169,7 +169,7 @@ Using this, it is possible to conveniently set up Unix shebang scripts. For exam For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/shebang -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [run](./cli-options.md#run-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [run](./cli-options.md#run-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ## SHOULD have commands: @@ -188,7 +188,7 @@ All standard Scala CLI inputs are accepted, but only Scala sources will be forma For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/fmt -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [fmt](./cli-options.md#fmt-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [fmt](./cli-options.md#fmt-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [workspace](./cli-options.md#workspace-options) ### test @@ -212,7 +212,7 @@ All supported types of inputs can be mixed with each other. For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/test -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [test](./cli-options.md#test-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [test](./cli-options.md#test-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ### version @@ -244,7 +244,7 @@ It is normally supposed to be invoked by your IDE when a Scala CLI project is im Detailed documentation can be found on our website: https://scala-cli.virtuslab.org -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [bsp](./cli-options.md#bsp-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [bsp](./cli-options.md#bsp-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [workspace](./cli-options.md#workspace-options) ### clean @@ -296,7 +296,7 @@ Using directives can be defined in all supported input source file types. For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/setup-ide -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [bsp file](./cli-options.md#bsp-file-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [setup IDE](./cli-options.md#setup-ide-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [bsp file](./cli-options.md#bsp-file-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [setup IDE](./cli-options.md#setup-ide-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [workspace](./cli-options.md#workspace-options) ### uninstall diff --git a/website/docs/reference/scala-command/runner-specification.md b/website/docs/reference/scala-command/runner-specification.md index d0a3a55050..4be6903a23 100644 --- a/website/docs/reference/scala-command/runner-specification.md +++ b/website/docs/reference/scala-command/runner-specification.md @@ -636,6 +636,12 @@ Show options for Scalafmt Aliases: `--help-fmt` ,`--scalafmt-help` ,`--fmt-help` +**--help-wasm** + +Show options for WebAssembly + +Aliases: `--wasm-help` + **--strict-bloop-json-check** @@ -1445,6 +1451,12 @@ Show options for Scalafmt Aliases: `--help-fmt` ,`--scalafmt-help` ,`--fmt-help` +**--help-wasm** + +Show options for WebAssembly + +Aliases: `--wasm-help` + **--strict-bloop-json-check** @@ -2070,6 +2082,12 @@ Show options for Scalafmt Aliases: `--help-fmt` ,`--scalafmt-help` ,`--fmt-help` +**--help-wasm** + +Show options for WebAssembly + +Aliases: `--wasm-help` + **--strict-bloop-json-check** @@ -2735,6 +2753,12 @@ Show options for Scalafmt Aliases: `--help-fmt` ,`--scalafmt-help` ,`--fmt-help` +**--help-wasm** + +Show options for WebAssembly + +Aliases: `--wasm-help` + **--strict-bloop-json-check** @@ -3399,6 +3423,12 @@ Show options for Scalafmt Aliases: `--help-fmt` ,`--scalafmt-help` ,`--fmt-help` +**--help-wasm** + +Show options for WebAssembly + +Aliases: `--wasm-help` + **--strict-bloop-json-check** @@ -4021,6 +4051,12 @@ Show options for Scalafmt Aliases: `--help-fmt` ,`--scalafmt-help` ,`--fmt-help` +**--help-wasm** + +Show options for WebAssembly + +Aliases: `--wasm-help` + **--strict-bloop-json-check** @@ -4721,6 +4757,12 @@ Show options for Scalafmt Aliases: `--help-fmt` ,`--scalafmt-help` ,`--fmt-help` +**--help-wasm** + +Show options for WebAssembly + +Aliases: `--wasm-help` + **--strict-bloop-json-check** @@ -5431,6 +5473,12 @@ Show options for Scalafmt Aliases: `--help-fmt` ,`--scalafmt-help` ,`--fmt-help` +**--help-wasm** + +Show options for WebAssembly + +Aliases: `--wasm-help` + **--strict-bloop-json-check** @@ -6424,6 +6472,12 @@ Show options for Scalafmt Aliases: `--help-fmt` ,`--scalafmt-help` ,`--fmt-help` +**--help-wasm** + +Show options for WebAssembly + +Aliases: `--wasm-help` + **--strict-bloop-json-check** From 7c74ecb36de217624ebafebcd781c89b4cc95508 Mon Sep 17 00:00:00 2001 From: lostflydev Date: Sun, 19 Apr 2026 12:57:10 +0500 Subject: [PATCH 3/8] - Add Bun as a third WASM runtime (--wasm-runtime bun / //> using wasmRuntime bun) - Add BunNotFoundError with install hint - Add integration test for Bun (conditional on bun being on PATH) - Add actions/setup-node@v6 node-version:24 to all Linux integration test jobs: the default Node.js on ubuntu-24.04 runners is too old for Scala.js WASM GC (which requires Node.js >= 22). Matches docs-tests job which already pins node-version: 24 --- .github/workflows/ci.yml | 51 +++++++++++++++++++ .../scala/scala/build/internal/Runner.scala | 49 ++++++++++++++++++ .../scala/scala/cli/commands/run/Run.scala | 9 ++++ .../cli/commands/shared/WasmOptions.scala | 2 +- .../scala/build/errors/BunNotFoundError.scala | 5 ++ .../build/preprocessing/directives/Wasm.scala | 3 +- .../RunScalaJsTestDefinitions.scala | 24 +++++++++ .../scala/build/options/WasmRuntime.scala | 5 +- website/docs/reference/cli-options.md | 2 +- website/docs/reference/directives.md | 4 +- 10 files changed, 149 insertions(+), 5 deletions(-) create mode 100644 modules/core/src/main/scala/scala/build/errors/BunNotFoundError.scala diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3446258058..578a2acbe5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -158,6 +158,9 @@ jobs: if: env.SHOULD_RUN == 'true' with: jvm: "temurin:17" + - uses: actions/setup-node@v6 + with: + node-version: 24 - name: JVM integration tests if: env.SHOULD_RUN == 'true' run: ./mill -i integration.test.jvmBootstrapped @@ -196,6 +199,9 @@ jobs: if: env.SHOULD_RUN == 'true' with: jvm: "temurin:17" + - uses: actions/setup-node@v6 + with: + node-version: 24 - name: JVM integration tests if: env.SHOULD_RUN == 'true' run: ./mill -i integration.test.jvm @@ -234,6 +240,9 @@ jobs: if: env.SHOULD_RUN == 'true' with: jvm: "temurin:17" + - uses: actions/setup-node@v6 + with: + node-version: 24 - name: JVM integration tests if: env.SHOULD_RUN == 'true' run: ./mill -i integration.test.jvm @@ -272,6 +281,9 @@ jobs: if: env.SHOULD_RUN == 'true' with: jvm: "temurin:17" + - uses: actions/setup-node@v6 + with: + node-version: 24 - name: JVM integration tests if: env.SHOULD_RUN == 'true' run: ./mill -i integration.test.jvm @@ -310,6 +322,9 @@ jobs: if: env.SHOULD_RUN == 'true' with: jvm: "temurin:17" + - uses: actions/setup-node@v6 + with: + node-version: 24 - name: JVM integration tests if: env.SHOULD_RUN == 'true' run: ./mill -i integration.test.jvm @@ -348,6 +363,9 @@ jobs: if: env.SHOULD_RUN == 'true' with: jvm: "temurin:17" + - uses: actions/setup-node@v6 + with: + node-version: 24 - name: JVM integration tests if: env.SHOULD_RUN == 'true' run: ./mill -i integration.test.jvm @@ -436,6 +454,9 @@ jobs: with: name: linux-launchers path: artifacts/ + - uses: actions/setup-node@v6 + with: + node-version: 24 - name: Native integration tests if: env.SHOULD_RUN == 'true' run: ./mill -i nativeIntegrationTests @@ -482,6 +503,9 @@ jobs: with: name: linux-launchers path: artifacts/ + - uses: actions/setup-node@v6 + with: + node-version: 24 - name: Native integration tests if: env.SHOULD_RUN == 'true' run: ./mill -i nativeIntegrationTests @@ -528,6 +552,9 @@ jobs: with: name: linux-launchers path: artifacts/ + - uses: actions/setup-node@v6 + with: + node-version: 24 - name: Native integration tests if: env.SHOULD_RUN == 'true' run: ./mill -i nativeIntegrationTests @@ -574,6 +601,9 @@ jobs: with: name: linux-launchers path: artifacts/ + - uses: actions/setup-node@v6 + with: + node-version: 24 - name: Native integration tests if: env.SHOULD_RUN == 'true' run: ./mill -i nativeIntegrationTests @@ -620,6 +650,9 @@ jobs: with: name: linux-launchers path: artifacts/ + - uses: actions/setup-node@v6 + with: + node-version: 24 - name: Native integration tests if: env.SHOULD_RUN == 'true' run: ./mill -i nativeIntegrationTests @@ -713,6 +746,9 @@ jobs: with: name: linux-aarch64-launchers path: artifacts/ + - uses: actions/setup-node@v6 + with: + node-version: 24 - name: Native integration tests if: env.SHOULD_RUN == 'true' run: ./mill -i nativeIntegrationTests @@ -759,6 +795,9 @@ jobs: with: name: linux-aarch64-launchers path: artifacts/ + - uses: actions/setup-node@v6 + with: + node-version: 24 - name: Native integration tests if: env.SHOULD_RUN == 'true' run: ./mill -i nativeIntegrationTests @@ -1417,6 +1456,9 @@ jobs: - name: Build slim docker image if: env.SHOULD_RUN == 'true' run: .github/scripts/generate-slim-docker-image.sh + - uses: actions/setup-node@v6 + with: + node-version: 24 - name: Native integration tests if: env.SHOULD_RUN == 'true' run: ./mill -i integration.test.nativeMostlyStatic @@ -1475,6 +1517,9 @@ jobs: with: name: mostly-static-launchers path: artifacts/ + - uses: actions/setup-node@v6 + with: + node-version: 24 - name: Native integration tests if: env.SHOULD_RUN == 'true' run: ./mill -i integration.test.nativeMostlyStatic @@ -1563,6 +1608,9 @@ jobs: - name: Build docker image if: env.SHOULD_RUN == 'true' run: .github/scripts/generate-docker-image.sh + - uses: actions/setup-node@v6 + with: + node-version: 24 - name: Native integration tests if: env.SHOULD_RUN == 'true' run: ./mill -i integration.test.nativeStatic @@ -1624,6 +1672,9 @@ jobs: - name: Build docker image if: env.SHOULD_RUN == 'true' run: .github/scripts/generate-docker-image.sh + - uses: actions/setup-node@v6 + with: + node-version: 24 - name: Native integration tests if: env.SHOULD_RUN == 'true' run: ./mill -i integration.test.nativeStatic diff --git a/modules/build/src/main/scala/scala/build/internal/Runner.scala b/modules/build/src/main/scala/scala/build/internal/Runner.scala index dc8e274fa6..9fee67a7d0 100644 --- a/modules/build/src/main/scala/scala/build/internal/Runner.scala +++ b/modules/build/src/main/scala/scala/build/internal/Runner.scala @@ -435,6 +435,55 @@ object Runner { } } + def bunCommand( + entrypoint: File, + args: Seq[String] + ): Seq[String] = { + val bunPath = findInPath("bun").fold("bun")(_.toString) + Seq(bunPath, "run", entrypoint.getAbsolutePath) ++ args + } + + def runBun( + entrypoint: File, + args: Seq[String], + logger: Logger, + allowExecve: Boolean = false + ): Either[BuildException, Process] = either { + val bunPath: String = + value(findInPath("bun") + .map(_.toString) + .toRight(BunNotFoundError())) + + val command = Seq(bunPath, "run", entrypoint.getAbsolutePath) ++ args + + if (allowExecve && Execve.available()) { + logger.log( + s"Running ${command.mkString(" ")}", + " Running" + System.lineSeparator() + + command.iterator.map(_ + System.lineSeparator()).mkString + ) + + logger.debug("execve available") + Execve.execve( + command.head, + "bun" +: command.tail.toArray, + sys.env.toArray.sorted.map { case (k, v) => s"$k=$v" } + ) + sys.error("should not happen") + } + else { + logger.log( + s"Running ${command.mkString(" ")}", + " Running" + System.lineSeparator() + + command.iterator.map(_ + System.lineSeparator()).mkString + ) + + new ProcessBuilder(command*) + .inheritIO() + .start() + } + } + def runNative( launcher: File, args: Seq[String], diff --git a/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala b/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala index c8253ee14e..e7a4be4161 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala @@ -508,6 +508,8 @@ object Run extends ScalaCommand[RunOptions] with BuildCommandHelpers { Left(Runner.denoCommand(outputPath.toIO, args)) case WasmRuntime.Node => Left(Runner.jsCommand(outputPath.toIO, args, jsDom = false, emitWasm = true)) + case WasmRuntime.Bun => + Left(Runner.bunCommand(outputPath.toIO, args)) } else { val process = value { @@ -531,6 +533,13 @@ object Run extends ScalaCommand[RunOptions] with BuildCommandHelpers { esModule = esModule, emitWasm = true ) + case WasmRuntime.Bun => + Runner.runBun( + outputPath.toIO, + args, + logger, + allowExecve = effectiveAllowExecve + ) } } process.onExit().thenApply(_ => if os.exists(jsDest) then os.remove(jsDest)) diff --git a/modules/cli/src/main/scala/scala/cli/commands/shared/WasmOptions.scala b/modules/cli/src/main/scala/scala/cli/commands/shared/WasmOptions.scala index a2e6251fdc..da99420d95 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/shared/WasmOptions.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/shared/WasmOptions.scala @@ -15,7 +15,7 @@ final case class WasmOptions( @Group(HelpGroup.Wasm.toString) @Tag(tags.experimental) - @HelpMessage("WASM runtime to use: node (default), deno") + @HelpMessage("WASM runtime to use: node (default), deno, bun") wasmRuntime: Option[String] = None ) // format: on diff --git a/modules/core/src/main/scala/scala/build/errors/BunNotFoundError.scala b/modules/core/src/main/scala/scala/build/errors/BunNotFoundError.scala new file mode 100644 index 0000000000..b6665fef28 --- /dev/null +++ b/modules/core/src/main/scala/scala/build/errors/BunNotFoundError.scala @@ -0,0 +1,5 @@ +package scala.build.errors + +final class BunNotFoundError extends BuildException( + "Bun was not found on the PATH. Install Bun from https://bun.sh/ or use --wasm-runtime node" + ) \ No newline at end of file diff --git a/modules/directives/src/main/scala/scala/build/preprocessing/directives/Wasm.scala b/modules/directives/src/main/scala/scala/build/preprocessing/directives/Wasm.scala index 9a1b7f67f9..d8c959f6fb 100644 --- a/modules/directives/src/main/scala/scala/build/preprocessing/directives/Wasm.scala +++ b/modules/directives/src/main/scala/scala/build/preprocessing/directives/Wasm.scala @@ -10,6 +10,7 @@ import scala.cli.commands.SpecificationLevel @DirectiveExamples("//> using wasm") @DirectiveExamples("//> using wasmRuntime node") @DirectiveExamples("//> using wasmRuntime deno") +@DirectiveExamples("//> using wasmRuntime bun") @DirectiveUsage( "//> using wasm|wasmRuntime _value_", """ @@ -17,7 +18,7 @@ import scala.cli.commands.SpecificationLevel | |`//> using wasm` | - |`//> using wasmRuntime` _node|deno_ + |`//> using wasmRuntime` _node|deno|bun_ |""".stripMargin ) @DirectiveDescription("Add WebAssembly options") diff --git a/modules/integration/src/test/scala/scala/cli/integration/RunScalaJsTestDefinitions.scala b/modules/integration/src/test/scala/scala/cli/integration/RunScalaJsTestDefinitions.scala index 7ff3972f7a..962091e74f 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/RunScalaJsTestDefinitions.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/RunScalaJsTestDefinitions.scala @@ -452,6 +452,30 @@ trait RunScalaJsTestDefinitions { this: RunTestDefinitions => } } + if (TestUtil.fromPath("bun").isDefined) + test("Run with --wasm-runtime bun") { + val inputs = TestInputs( + os.rel / "Hello.scala" -> + """object Hello { + | def main(args: Array[String]): Unit = println("Hello from Bun WASM!") + |} + |""".stripMargin + ) + inputs.fromRoot { root => + val output = os.proc( + TestUtil.cli, + "--power", + "run", + "Hello.scala", + "--wasm", + "--wasm-runtime", + "bun", + extraOptions + ).call(cwd = root).out.trim() + expect(output == "Hello from Bun WASM!") + } + } + test("WASM multiple source files") { val inputs = TestInputs( os.rel / "Greeter.scala" -> diff --git a/modules/options/src/main/scala/scala/build/options/WasmRuntime.scala b/modules/options/src/main/scala/scala/build/options/WasmRuntime.scala index a2e68d63f8..b5f8814e5d 100644 --- a/modules/options/src/main/scala/scala/build/options/WasmRuntime.scala +++ b/modules/options/src/main/scala/scala/build/options/WasmRuntime.scala @@ -7,14 +7,16 @@ import java.util.Locale * JS-based runtimes (work now with Scala.js WASM backend): * - Node: Uses Node.js (V8 engine) with JavaScript loader * - Deno: Uses Deno (V8 engine) with ES module support + * - Bun: Uses Bun (JavaScriptCore engine) with ES module support */ sealed abstract class WasmRuntime(val name: String) object WasmRuntime { case object Node extends WasmRuntime("node") case object Deno extends WasmRuntime("deno") + case object Bun extends WasmRuntime("bun") - val all: Seq[WasmRuntime] = Seq(Node, Deno) + val all: Seq[WasmRuntime] = Seq(Node, Deno, Bun) def default: WasmRuntime = Node @@ -22,6 +24,7 @@ object WasmRuntime { s.trim.toLowerCase(Locale.ROOT) match { case "node" | "nodejs" => Some(Node) case "deno" => Some(Deno) + case "bun" => Some(Bun) case _ => None } diff --git a/website/docs/reference/cli-options.md b/website/docs/reference/cli-options.md index 4ea7797d64..5384fdf679 100644 --- a/website/docs/reference/cli-options.md +++ b/website/docs/reference/cli-options.md @@ -1986,7 +1986,7 @@ Enable WebAssembly output (Scala.js WASM backend). Uses Node.js by default. To s ### `--wasm-runtime` -WASM runtime to use: node (default), deno +WASM runtime to use: node (default), deno, bun ## Watch options diff --git a/website/docs/reference/directives.md b/website/docs/reference/directives.md index cf75f0cbaf..d9640d57bf 100644 --- a/website/docs/reference/directives.md +++ b/website/docs/reference/directives.md @@ -716,7 +716,7 @@ Add WebAssembly options `//> using wasm` -`//> using wasmRuntime` _node|deno_ +`//> using wasmRuntime` _node|deno|bun_ #### Examples @@ -726,6 +726,8 @@ Add WebAssembly options `//> using wasmRuntime deno` +`//> using wasmRuntime bun` + ### Watch additional inputs Watch additional files or directories when using watch mode From 565048e435aba63e68856cfce08f9b5e487510be Mon Sep 17 00:00:00 2001 From: lostflydev Date: Wed, 6 May 2026 11:54:26 +0300 Subject: [PATCH 4/8] Always pass --experimental-wasm-exnref when emitting WASM Node 24 still ships V8 12.x where wasm-exnref is gated behind --experimental-wasm-exnref; the flag only flips to default in V8 13.x (Node 25+). The previous nodeMajorVersion < 24 guard therefore left Node 24 (the version pinned in CI) without the flag, which made any Scala.js WASM code using exception bytecodes, runtime throws, JS interop or Scala 3 @main fail at runtime. Same reasoning applies to Deno (Deno 2.x = V8 12.x). Until V8 13.x is the default everywhere, just always set the flag, there is no any overhead --- .../scala/scala/build/internal/Runner.scala | 39 +++++++++++-------- .../scala/scala/cli/commands/run/Run.scala | 4 +- .../scala/build/errors/BunNotFoundError.scala | 2 +- .../errors/BunVersionTooOldForWasmError.scala | 7 ++++ .../NodeVersionTooOldForWasmError.scala | 7 ++++ 5 files changed, 40 insertions(+), 19 deletions(-) create mode 100644 modules/core/src/main/scala/scala/build/errors/BunVersionTooOldForWasmError.scala create mode 100644 modules/core/src/main/scala/scala/build/errors/NodeVersionTooOldForWasmError.scala diff --git a/modules/build/src/main/scala/scala/build/internal/Runner.scala b/modules/build/src/main/scala/scala/build/internal/Runner.scala index 9fee67a7d0..e87e7e7786 100644 --- a/modules/build/src/main/scala/scala/build/internal/Runner.scala +++ b/modules/build/src/main/scala/scala/build/internal/Runner.scala @@ -210,24 +210,26 @@ object Runner { case _: Exception => None } - // Node 24+ (V8 13+) has wasm-exnref enabled by default; older versions need --experimental-wasm-exnref. - private def nodeNeedsWasmFlag: Boolean = - nodeMajorVersion.forall(_ < 24) // true if unknown or < 24 - - // Detects the major version of Deno on PATH; cached for the JVM lifetime (lazy val). - // Returns None if deno is not found or version cannot be parsed. - private lazy val denoMajorVersion: Option[Int] = + // Pre-V8 13.x runtimes need --experimental-wasm-exnref for the Scala.js WASM exception model. + // V8 13.x ships in Node 25+ (Node 24 is still on V8 12.x where exnref is gated behind the flag), + // so until the default flips we always pass the flag when emitWasm is true. + private def nodeNeedsWasmFlag: Boolean = true + + // Deno 2.x bundles V8 12.x where wasm-exnref is gated behind a flag; symmetrical reasoning to Node. + // We always set DENO_V8_FLAGS=--experimental-wasm-exnref on emitWasm until V8 13.x lands in Deno. + private def denoNeedsWasmFlag: Boolean = true + + // Detects the major version of Bun on PATH; cached for the JVM lifetime (lazy val). + // Returns None if bun is not found or version cannot be parsed. + private lazy val bunMajorVersion: Option[Int] = try { - val process = new ProcessBuilder("deno", "--version") + val process = new ProcessBuilder("bun", "--version") .redirectErrorStream(true) .start() val output = new String(process.getInputStream.readAllBytes()).trim process.waitFor() - // Deno version format: "deno 2.1.0 (release, aarch64-apple-darwin)\nv8 13.x\ntypescript 5.x" - // Extract major from first line - val firstLine = output.linesIterator.nextOption().getOrElse("") - val versionStr = firstLine.stripPrefix("deno ").takeWhile(c => c.isDigit || c == '.') - versionStr.takeWhile(_.isDigit) match { + // Bun version format: "1.1.30" -> extract 1 + output.takeWhile(_.isDigit) match { case s if s.nonEmpty => Some(s.toInt) case _ => None } @@ -236,10 +238,6 @@ object Runner { case _: Exception => None } - // Deno 2.x+ bundles V8 13+ which has wasm-exnref enabled by default; no flag needed. - private def denoNeedsWasmFlag: Boolean = - denoMajorVersion.forall(_ < 2) // true if unknown or < 2 - private def endsWithCaseInsensitive(s: String, suffix: String): Boolean = s.length >= suffix.length && s.regionMatches(true, s.length - suffix.length, suffix, 0, suffix.length) @@ -302,6 +300,10 @@ object Runner { value(findInPath("node") .map(_.toString) .toRight(NodeNotFoundError())) + if (emitWasm) + nodeMajorVersion.foreach { v => + if (v < 22) value(Left(new NodeVersionTooOldForWasmError(v))) + } val nodeFlags = if (emitWasm && nodeNeedsWasmFlag) List("--experimental-wasm-exnref") else Nil if !jsDom && allowExecve && Execve.available() then { val command = Seq(nodePath) ++ nodeFlags ++ Seq(entrypoint.getAbsolutePath) ++ args @@ -453,6 +455,9 @@ object Runner { value(findInPath("bun") .map(_.toString) .toRight(BunNotFoundError())) + bunMajorVersion.foreach { v => + if (v < 1) value(Left(new BunVersionTooOldForWasmError(v))) + } val command = Seq(bunPath, "run", entrypoint.getAbsolutePath) ++ args diff --git a/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala b/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala index e7a4be4161..4e04a3d798 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala @@ -552,7 +552,9 @@ object Run extends ScalaCommand[RunOptions] with BuildCommandHelpers { build.options.platform.value match { case Platform.JS => val esModule = - build.options.scalaJsOptions.moduleKindStr.exists(m => m == "es" || m == "esmodule") + build.options.scalaJsOptions.moduleKindStr.exists(m => + m == "es" || m == "esmodule" + ) val linkerConfig = build.options.scalaJsOptions.linkerConfig(logger) val jsDest = { diff --git a/modules/core/src/main/scala/scala/build/errors/BunNotFoundError.scala b/modules/core/src/main/scala/scala/build/errors/BunNotFoundError.scala index b6665fef28..d5db2865a6 100644 --- a/modules/core/src/main/scala/scala/build/errors/BunNotFoundError.scala +++ b/modules/core/src/main/scala/scala/build/errors/BunNotFoundError.scala @@ -2,4 +2,4 @@ package scala.build.errors final class BunNotFoundError extends BuildException( "Bun was not found on the PATH. Install Bun from https://bun.sh/ or use --wasm-runtime node" - ) \ No newline at end of file + ) diff --git a/modules/core/src/main/scala/scala/build/errors/BunVersionTooOldForWasmError.scala b/modules/core/src/main/scala/scala/build/errors/BunVersionTooOldForWasmError.scala new file mode 100644 index 0000000000..5386aa56a6 --- /dev/null +++ b/modules/core/src/main/scala/scala/build/errors/BunVersionTooOldForWasmError.scala @@ -0,0 +1,7 @@ +package scala.build.errors + +final class BunVersionTooOldForWasmError(found: Int) + extends BuildException( + s"Scala.js WASM backend requires Bun >= 1, but found Bun $found. " + + "Upgrade Bun (https://bun.sh/) or switch runtime via --wasm-runtime node|deno." + ) diff --git a/modules/core/src/main/scala/scala/build/errors/NodeVersionTooOldForWasmError.scala b/modules/core/src/main/scala/scala/build/errors/NodeVersionTooOldForWasmError.scala new file mode 100644 index 0000000000..d1a48562d9 --- /dev/null +++ b/modules/core/src/main/scala/scala/build/errors/NodeVersionTooOldForWasmError.scala @@ -0,0 +1,7 @@ +package scala.build.errors + +final class NodeVersionTooOldForWasmError(found: Int) + extends BuildException( + s"Scala.js WASM backend requires Node.js >= 22, but found Node.js $found. " + + "Upgrade Node (https://nodejs.org/) or switch runtime via --wasm-runtime deno|bun." + ) From 479982700955f1422afebb0ea23bc68368a223f4 Mon Sep 17 00:00:00 2001 From: lostflydev Date: Thu, 14 May 2026 18:47:27 +0500 Subject: [PATCH 5/8] Fix review feedback: Wasm capitalization, version-aware node flags, refactor into ScalaJsOptions - Replace "WASM" with "Wasm" per WebAssembly spec: contraction, not acronym - Fix nodeNeedsWasmFlag to be version-aware: only pass --experimental-wasm-exnref for Node < 25 (V8 12.x); Node 25+ has it enabled by default, Node 26+ may remove it - Remove Node/Bun pre-flight version checks; let runtime fail naturally on old versions - Remove else-if-emitWasm branch (not needed) - Refactor WasmOptions into ScalaJsOptions: jsEmitWasm and wasmRuntime are now fields of ScalaJsOptions at both build and CLI layers; CLI flags are now --js-emit-wasm and --js-wasm-runtime under the Wasm help group; WasmOptions classes removed - linkerConfig() now forces ESModule when jsEmitWasm=true - Update all integration test CLI flags to --js-emit-wasm / --js-wasm-runtime --- .../scala/scala/build/internal/Runner.scala | 51 ++--------- .../scala/scala/cli/commands/run/Run.scala | 19 ++--- .../cli/commands/shared/ScalaJsOptions.scala | 9 +- .../cli/commands/shared/SharedOptions.scala | 85 +++++++++---------- .../cli/commands/shared/WasmOptions.scala | 27 ------ .../scala/build/errors/BunNotFoundError.scala | 2 +- .../errors/BunVersionTooOldForWasmError.scala | 7 -- .../build/errors/DenoNotFoundError.scala | 2 +- .../NodeVersionTooOldForWasmError.scala | 7 -- .../errors/UnrecognizedWasmRuntimeError.scala | 2 +- .../build/preprocessing/directives/Wasm.scala | 15 ++-- .../RunScalaJsTestDefinitions.scala | 52 ++++++------ .../scala/build/options/BuildOptions.scala | 1 - .../scala/build/options/ScalaJsOptions.scala | 6 +- .../scala/build/options/WasmOptions.scala | 18 ---- .../scala/build/options/WasmRuntime.scala | 2 +- website/docs/reference/cli-options.md | 22 ++--- website/docs/reference/commands.md | 30 +++---- website/docs/reference/directives.md | 2 +- .../reference/scala-command/cli-options.md | 10 --- .../docs/reference/scala-command/commands.md | 18 ++-- 21 files changed, 131 insertions(+), 256 deletions(-) delete mode 100644 modules/cli/src/main/scala/scala/cli/commands/shared/WasmOptions.scala delete mode 100644 modules/core/src/main/scala/scala/build/errors/BunVersionTooOldForWasmError.scala delete mode 100644 modules/core/src/main/scala/scala/build/errors/NodeVersionTooOldForWasmError.scala delete mode 100644 modules/options/src/main/scala/scala/build/options/WasmOptions.scala diff --git a/modules/build/src/main/scala/scala/build/internal/Runner.scala b/modules/build/src/main/scala/scala/build/internal/Runner.scala index e87e7e7786..d5c4d7585c 100644 --- a/modules/build/src/main/scala/scala/build/internal/Runner.scala +++ b/modules/build/src/main/scala/scala/build/internal/Runner.scala @@ -210,34 +210,16 @@ object Runner { case _: Exception => None } - // Pre-V8 13.x runtimes need --experimental-wasm-exnref for the Scala.js WASM exception model. - // V8 13.x ships in Node 25+ (Node 24 is still on V8 12.x where exnref is gated behind the flag), - // so until the default flips we always pass the flag when emitWasm is true. - private def nodeNeedsWasmFlag: Boolean = true + // Pre-V8 13.x runtimes need --experimental-wasm-exnref for the Scala.js Wasm exception model. + // V8 13.x ships in Node 25+ (Node 24 is still on V8 12.x where exnref is gated behind the flag). + // In Node 26+, the flag may be removed from the CLI. Only pass it when Node < 25. + // None.forall(_ < 25) == true — safe fallback when version detection fails. + private def nodeNeedsWasmFlag: Boolean = nodeMajorVersion.forall(_ < 25) // Deno 2.x bundles V8 12.x where wasm-exnref is gated behind a flag; symmetrical reasoning to Node. - // We always set DENO_V8_FLAGS=--experimental-wasm-exnref on emitWasm until V8 13.x lands in Deno. + // We always set DENO_V8_FLAGS=--experimental-wasm-exnref on Wasm output until V8 13.x lands in Deno. private def denoNeedsWasmFlag: Boolean = true - // Detects the major version of Bun on PATH; cached for the JVM lifetime (lazy val). - // Returns None if bun is not found or version cannot be parsed. - private lazy val bunMajorVersion: Option[Int] = - try { - val process = new ProcessBuilder("bun", "--version") - .redirectErrorStream(true) - .start() - val output = new String(process.getInputStream.readAllBytes()).trim - process.waitFor() - // Bun version format: "1.1.30" -> extract 1 - output.takeWhile(_.isDigit) match { - case s if s.nonEmpty => Some(s.toInt) - case _ => None - } - } - catch { - case _: Exception => None - } - private def endsWithCaseInsensitive(s: String, suffix: String): Boolean = s.length >= suffix.length && s.regionMatches(true, s.length - suffix.length, suffix, 0, suffix.length) @@ -300,10 +282,6 @@ object Runner { value(findInPath("node") .map(_.toString) .toRight(NodeNotFoundError())) - if (emitWasm) - nodeMajorVersion.foreach { v => - if (v < 22) value(Left(new NodeVersionTooOldForWasmError(v))) - } val nodeFlags = if (emitWasm && nodeNeedsWasmFlag) List("--experimental-wasm-exnref") else Nil if !jsDom && allowExecve && Execve.available() then { val command = Seq(nodePath) ++ nodeFlags ++ Seq(entrypoint.getAbsolutePath) ++ args @@ -322,19 +300,6 @@ object Runner { ) sys.error("should not happen") } - else if (emitWasm) { - // For WASM mode with ES modules, run node directly instead of NodeJSEnv. - // NodeJSEnv's stdin piping with "-" doesn't work with Input.ESModule. - val command = Seq(nodePath) ++ nodeFlags ++ Seq(entrypoint.getAbsolutePath) ++ args - - logger.log( - s"Running ${command.mkString(" ")}", - " Running" + System.lineSeparator() + - command.iterator.map(_ + System.lineSeparator()).mkString - ) - - new ProcessBuilder(command: _*).inheritIO().start() - } else { val nodeArgs = // Scala.js runs apps by piping JS to node. @@ -455,10 +420,6 @@ object Runner { value(findInPath("bun") .map(_.toString) .toRight(BunNotFoundError())) - bunMajorVersion.foreach { v => - if (v < 1) value(Left(new BunVersionTooOldForWasmError(v))) - } - val command = Seq(bunPath, "run", entrypoint.getAbsolutePath) ++ args if (allowExecve && Execve.available()) { diff --git a/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala b/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala index 4e04a3d798..0a4467ee86 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala @@ -474,12 +474,12 @@ object Run extends ScalaCommand[RunOptions] with BuildCommandHelpers { if shouldLogCrossInfo then logger.debug(s"Running build for ${crossBuildParams.asString}") val build = builds.head either { - val wasmOpts = build.options.wasmOptions + val jsOpts = build.options.scalaJsOptions - // Check if WASM mode is requested - if wasmOpts.enabled then { - val runtime = wasmOpts.runtime - val esModule = true // WASM backend uses ES modules + // Check if Wasm mode is requested + if jsOpts.jsEmitWasm then { + val runtime = jsOpts.wasmRuntime + val esModule = true // Wasm backend uses ES modules scratchDirOpt.foreach(os.makeDir.all(_)) val jsDest = os.temp( dir = scratchDirOpt.orNull, @@ -488,8 +488,7 @@ object Run extends ScalaCommand[RunOptions] with BuildCommandHelpers { deleteOnExit = scratchDirOpt.isEmpty ) - val linkerConfig = build.options.scalaJsOptions.linkerConfig(logger) - .copy(emitWasm = true, moduleKind = ScalaJsLinkerConfig.ModuleKind.ESModule) + val linkerConfig = jsOpts.linkerConfig(logger) val res = Package.linkJs( builds = builds, @@ -497,8 +496,8 @@ object Run extends ScalaCommand[RunOptions] with BuildCommandHelpers { mainClassOpt = Some(mainClass), addTestInitializer = false, config = linkerConfig, - fullOpt = value(build.options.scalaJsOptions.fullOpt), - noOpt = build.options.scalaJsOptions.noOpt.getOrElse(false), + fullOpt = value(jsOpts.fullOpt), + noOpt = jsOpts.noOpt.getOrElse(false), logger = logger, scratchDirOpt = scratchDirOpt ).map { outputPath => @@ -529,7 +528,7 @@ object Run extends ScalaCommand[RunOptions] with BuildCommandHelpers { logger, allowExecve = effectiveAllowExecve, jsDom = false, - sourceMap = build.options.scalaJsOptions.emitSourceMaps, + sourceMap = jsOpts.emitSourceMaps, esModule = esModule, emitWasm = true ) diff --git a/modules/cli/src/main/scala/scala/cli/commands/shared/ScalaJsOptions.scala b/modules/cli/src/main/scala/scala/cli/commands/shared/ScalaJsOptions.scala index 96045c4eec..2a8aae990e 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/shared/ScalaJsOptions.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/shared/ScalaJsOptions.scala @@ -59,11 +59,16 @@ final case class ScalaJsOptions( @HelpMessage("Enable jsdom") jsDom: Option[Boolean] = None, - @Group(HelpGroup.ScalaJs.toString) + @Group(HelpGroup.Wasm.toString) @Tag(tags.experimental) - @HelpMessage("Emit WASM") + @HelpMessage("Enable Wasm output (Scala.js Wasm backend). Uses Node.js by default. To show more options for Wasm pass `--help-wasm`") jsEmitWasm: Option[Boolean] = None, + @Group(HelpGroup.Wasm.toString) + @Tag(tags.experimental) + @HelpMessage("Wasm runtime to use: node (default), deno, bun") + jsWasmRuntime: Option[String] = None, + @Group(HelpGroup.ScalaJs.toString) @Tag(tags.should) @HelpMessage("A header that will be added at the top of generated .js files") diff --git a/modules/cli/src/main/scala/scala/cli/commands/shared/SharedOptions.scala b/modules/cli/src/main/scala/scala/cli/commands/shared/SharedOptions.scala index 9c988b6dca..d81a8b8f48 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/shared/SharedOptions.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/shared/SharedOptions.scala @@ -57,8 +57,6 @@ final case class SharedOptions( js: ScalaJsOptions = ScalaJsOptions(), @Recurse native: ScalaNativeOptions = ScalaNativeOptions(), - @Recurse - wasmOptions: WasmOptions = WasmOptions(), @Recurse compilationServer: SharedCompilationServerOptions = SharedCompilationServerOptions(), @Recurse @@ -249,26 +247,40 @@ final case class SharedOptions( ) .getOrElse(true) - private def scalaJsOptions(opts: ScalaJsOptions): options.ScalaJsOptions = { + private def scalaJsOptions( + opts: ScalaJsOptions + ): Either[BuildException, options.ScalaJsOptions] = { import opts._ - options.ScalaJsOptions( - version = jsVersion, - mode = options.ScalaJsMode(jsMode), - moduleKindStr = jsModuleKind, - checkIr = jsCheckIr, - emitSourceMaps = jsEmitSourceMaps, - sourceMapsDest = jsSourceMapsPath.filter(_.trim.nonEmpty).map(os.Path(_, Os.pwd)), - dom = jsDom, - header = jsHeader, - allowBigIntsForLongs = jsAllowBigIntsForLongs, - avoidClasses = jsAvoidClasses, - avoidLetsAndConsts = jsAvoidLetsAndConsts, - moduleSplitStyleStr = jsModuleSplitStyle, - smallModuleForPackage = jsSmallModuleForPackage, - esVersionStr = jsEsVersion, - noOpt = jsNoOpt, - remapEsModuleImportMap = jsEsModuleImportMap.filter(_.trim.nonEmpty).map(os.Path(_, Os.pwd)), - jsEmitWasm = jsEmitWasm.getOrElse(false) + val parsedWasmRuntime = jsWasmRuntime.fold( + Right(options.WasmRuntime.default): Either[BuildException, options.WasmRuntime] + ) { rt => + options.WasmRuntime.parse(rt).toRight { + val validValues = options.WasmRuntime.all.map(_.name).mkString(", ") + new scala.build.errors.UnrecognizedWasmRuntimeError(rt, validValues) + } + } + parsedWasmRuntime.map(wasmRuntime => + options.ScalaJsOptions( + version = jsVersion, + mode = options.ScalaJsMode(jsMode), + moduleKindStr = jsModuleKind, + checkIr = jsCheckIr, + emitSourceMaps = jsEmitSourceMaps, + sourceMapsDest = jsSourceMapsPath.filter(_.trim.nonEmpty).map(os.Path(_, Os.pwd)), + dom = jsDom, + header = jsHeader, + allowBigIntsForLongs = jsAllowBigIntsForLongs, + avoidClasses = jsAvoidClasses, + avoidLetsAndConsts = jsAvoidLetsAndConsts, + moduleSplitStyleStr = jsModuleSplitStyle, + smallModuleForPackage = jsSmallModuleForPackage, + esVersionStr = jsEsVersion, + noOpt = jsNoOpt, + remapEsModuleImportMap = + jsEsModuleImportMap.filter(_.trim.nonEmpty).map(os.Path(_, Os.pwd)), + jsEmitWasm = jsEmitWasm.getOrElse(false), + wasmRuntime = wasmRuntime + ) ) } @@ -313,26 +325,6 @@ final case class SharedOptions( ) } - private def buildWasmOptions( - opts: WasmOptions - ): Either[BuildException, options.WasmOptions] = { - import opts._ - val wasmEnabled = wasm || wasmRuntime.isDefined - val parsedRuntime: Either[BuildException, options.WasmRuntime] = - wasmRuntime.fold(Right(options.WasmRuntime.default)) { rt => - options.WasmRuntime.parse(rt).toRight { - val validValues = options.WasmRuntime.all.map(_.name).mkString(", ") - new scala.build.errors.UnrecognizedWasmRuntimeError(rt, validValues) - } - } - parsedRuntime.map(runtime => - options.WasmOptions( - enabled = wasmEnabled, - runtime = runtime - ) - ) - } - lazy val scalacOptionsFromFiles: List[String] = scalac.argsFiles.flatMap(argFile => ArgSplitter.splitToArgs(os.read(os.Path(argFile.file, os.pwd))) @@ -357,8 +349,8 @@ final case class SharedOptions( case _ => } val parsedPlatform = platform.map(Platform.normalize).flatMap(Platform.parse) - // WASM mode requires Scala.js platform for compilation - val wasmEnabled = wasmOptions.wasm || wasmOptions.wasmRuntime.isDefined + // Wasm mode requires Scala.js platform for compilation + val wasmEnabled = js.jsEmitWasm.getOrElse(false) || js.jsWasmRuntime.isDefined val platformOpt = value { (parsedPlatform, js.js, native.native, wasmEnabled) match { case (Some(p: Platform.JS.type), _, false, _) => Right(Some(p)) @@ -372,10 +364,10 @@ final case class SharedOptions( case (_, true, true, _) => Left(new AmbiguousPlatformError(Seq(Platform.JS.toString, Platform.Native.toString))) case (_, _, true, true) => - Left(new AmbiguousPlatformError(Seq(Platform.Native.toString, "WASM (requires JS)"))) + Left(new AmbiguousPlatformError(Seq(Platform.Native.toString, "Wasm (requires JS)"))) case (_, true, _, _) => Right(Some(Platform.JS)) case (_, _, _, true) => - Right(Some(Platform.JS)) // WASM requires JS compilation (Scala.js WASM backend) + Right(Some(Platform.JS)) // Wasm requires JS compilation (Scala.js Wasm backend) case (_, _, true, _) => Right(Some(Platform.Native)) case _ => Right(None) } @@ -462,9 +454,8 @@ final case class SharedOptions( scriptOptions = scala.build.options.ScriptOptions( forceObjectWrapper = objectWrapper ), - scalaJsOptions = scalaJsOptions(js), + scalaJsOptions = value(scalaJsOptions(js)), scalaNativeOptions = snOpts, - wasmOptions = value(buildWasmOptions(wasmOptions)), javaOptions = value(scala.cli.commands.util.JvmUtils.javaOptions(jvm)), jmhOptions = scala.build.options.JmhOptions( jmhVersion = benchmarking.jmhVersion, diff --git a/modules/cli/src/main/scala/scala/cli/commands/shared/WasmOptions.scala b/modules/cli/src/main/scala/scala/cli/commands/shared/WasmOptions.scala deleted file mode 100644 index da99420d95..0000000000 --- a/modules/cli/src/main/scala/scala/cli/commands/shared/WasmOptions.scala +++ /dev/null @@ -1,27 +0,0 @@ -package scala.cli.commands.shared - -import caseapp.* -import com.github.plokhotnyuk.jsoniter_scala.core.* -import com.github.plokhotnyuk.jsoniter_scala.macros.* - -import scala.cli.commands.tags - -// format: off -final case class WasmOptions( - @Group(HelpGroup.Wasm.toString) - @Tag(tags.experimental) - @HelpMessage("Enable WebAssembly output (Scala.js WASM backend). Uses Node.js by default. To show more options for WASM pass `--help-wasm`") - wasm: Boolean = false, - - @Group(HelpGroup.Wasm.toString) - @Tag(tags.experimental) - @HelpMessage("WASM runtime to use: node (default), deno, bun") - wasmRuntime: Option[String] = None -) -// format: on - -object WasmOptions { - implicit lazy val parser: Parser[WasmOptions] = Parser.derive - implicit lazy val help: Help[WasmOptions] = Help.derive - implicit lazy val jsonCodec: JsonValueCodec[WasmOptions] = JsonCodecMaker.make -} diff --git a/modules/core/src/main/scala/scala/build/errors/BunNotFoundError.scala b/modules/core/src/main/scala/scala/build/errors/BunNotFoundError.scala index d5db2865a6..a67aaa586b 100644 --- a/modules/core/src/main/scala/scala/build/errors/BunNotFoundError.scala +++ b/modules/core/src/main/scala/scala/build/errors/BunNotFoundError.scala @@ -1,5 +1,5 @@ package scala.build.errors final class BunNotFoundError extends BuildException( - "Bun was not found on the PATH. Install Bun from https://bun.sh/ or use --wasm-runtime node" + "Bun was not found on the PATH. Install Bun from https://bun.sh/ or use --js-wasm-runtime node" ) diff --git a/modules/core/src/main/scala/scala/build/errors/BunVersionTooOldForWasmError.scala b/modules/core/src/main/scala/scala/build/errors/BunVersionTooOldForWasmError.scala deleted file mode 100644 index 5386aa56a6..0000000000 --- a/modules/core/src/main/scala/scala/build/errors/BunVersionTooOldForWasmError.scala +++ /dev/null @@ -1,7 +0,0 @@ -package scala.build.errors - -final class BunVersionTooOldForWasmError(found: Int) - extends BuildException( - s"Scala.js WASM backend requires Bun >= 1, but found Bun $found. " + - "Upgrade Bun (https://bun.sh/) or switch runtime via --wasm-runtime node|deno." - ) diff --git a/modules/core/src/main/scala/scala/build/errors/DenoNotFoundError.scala b/modules/core/src/main/scala/scala/build/errors/DenoNotFoundError.scala index 4566e346a4..cf9dc42b78 100644 --- a/modules/core/src/main/scala/scala/build/errors/DenoNotFoundError.scala +++ b/modules/core/src/main/scala/scala/build/errors/DenoNotFoundError.scala @@ -1,5 +1,5 @@ package scala.build.errors final class DenoNotFoundError extends BuildException( - "Deno was not found on the PATH. Install Deno from https://deno.land/ or use --wasm-runtime node" + "Deno was not found on the PATH. Install Deno from https://deno.land/ or use --js-wasm-runtime node" ) diff --git a/modules/core/src/main/scala/scala/build/errors/NodeVersionTooOldForWasmError.scala b/modules/core/src/main/scala/scala/build/errors/NodeVersionTooOldForWasmError.scala deleted file mode 100644 index d1a48562d9..0000000000 --- a/modules/core/src/main/scala/scala/build/errors/NodeVersionTooOldForWasmError.scala +++ /dev/null @@ -1,7 +0,0 @@ -package scala.build.errors - -final class NodeVersionTooOldForWasmError(found: Int) - extends BuildException( - s"Scala.js WASM backend requires Node.js >= 22, but found Node.js $found. " + - "Upgrade Node (https://nodejs.org/) or switch runtime via --wasm-runtime deno|bun." - ) diff --git a/modules/core/src/main/scala/scala/build/errors/UnrecognizedWasmRuntimeError.scala b/modules/core/src/main/scala/scala/build/errors/UnrecognizedWasmRuntimeError.scala index 46e2f43b6c..2d7b01db36 100644 --- a/modules/core/src/main/scala/scala/build/errors/UnrecognizedWasmRuntimeError.scala +++ b/modules/core/src/main/scala/scala/build/errors/UnrecognizedWasmRuntimeError.scala @@ -1,4 +1,4 @@ package scala.build.errors class UnrecognizedWasmRuntimeError(runtime: String, validValues: String) - extends BuildException(s"Unrecognized WASM runtime: '$runtime'. Valid values: $validValues") + extends BuildException(s"Unrecognized Wasm runtime: '$runtime'. Valid values: $validValues") diff --git a/modules/directives/src/main/scala/scala/build/preprocessing/directives/Wasm.scala b/modules/directives/src/main/scala/scala/build/preprocessing/directives/Wasm.scala index d8c959f6fb..932fafee89 100644 --- a/modules/directives/src/main/scala/scala/build/preprocessing/directives/Wasm.scala +++ b/modules/directives/src/main/scala/scala/build/preprocessing/directives/Wasm.scala @@ -3,10 +3,10 @@ package scala.build.preprocessing.directives import scala.build.Positioned import scala.build.directives.* import scala.build.errors.{BuildException, UnrecognizedWasmRuntimeError} -import scala.build.options.{BuildOptions, Platform, ScalaOptions, WasmOptions, WasmRuntime} +import scala.build.options.{BuildOptions, Platform, ScalaJsOptions, ScalaOptions, WasmRuntime} import scala.cli.commands.SpecificationLevel -@DirectiveGroupName("WASM options") +@DirectiveGroupName("Wasm options") @DirectiveExamples("//> using wasm") @DirectiveExamples("//> using wasmRuntime node") @DirectiveExamples("//> using wasmRuntime deno") @@ -37,17 +37,16 @@ final case class Wasm( } parsedRuntime.map { runtime => val wasmEnabled = wasm.getOrElse(false) || wasmRuntime.isDefined - val wasmOptions = WasmOptions( - enabled = wasmEnabled, - runtime = runtime - ) - // When WASM is enabled, force Platform.JS (Scala.js WASM backend requires JS compilation) + // When Wasm is enabled, force Platform.JS (Scala.js Wasm backend requires JS compilation) val scalaOptions = if (wasmEnabled) ScalaOptions(platform = Some(Positioned.none(Platform.JS))) else ScalaOptions() - BuildOptions(scalaOptions = scalaOptions, wasmOptions = wasmOptions) + BuildOptions( + scalaOptions = scalaOptions, + scalaJsOptions = ScalaJsOptions(jsEmitWasm = wasmEnabled, wasmRuntime = runtime) + ) } } } diff --git a/modules/integration/src/test/scala/scala/cli/integration/RunScalaJsTestDefinitions.scala b/modules/integration/src/test/scala/scala/cli/integration/RunScalaJsTestDefinitions.scala index 962091e74f..ba747a7a8b 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/RunScalaJsTestDefinitions.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/RunScalaJsTestDefinitions.scala @@ -328,7 +328,7 @@ trait RunScalaJsTestDefinitions { this: RunTestDefinitions => } } - test("Run with --wasm flag") { + test("Run with --js-emit-wasm flag") { val inputs = TestInputs( os.rel / "Hello.scala" -> """object Hello { @@ -342,8 +342,8 @@ trait RunScalaJsTestDefinitions { this: RunTestDefinitions => "--power", "run", "Hello.scala", - "--wasm", - "--wasm-runtime", + "--js-emit-wasm", + "--js-wasm-runtime", "node", extraOptions ).call(cwd = root).out.trim() @@ -351,7 +351,7 @@ trait RunScalaJsTestDefinitions { this: RunTestDefinitions => } } - test("Run with --wasm uses Node.js by default") { + test("Run with --js-emit-wasm uses Node.js by default") { val inputs = TestInputs( os.rel / "Hello.scala" -> """object Hello { @@ -365,7 +365,7 @@ trait RunScalaJsTestDefinitions { this: RunTestDefinitions => "--power", "run", "Hello.scala", - "--wasm", + "--js-emit-wasm", extraOptions ).call(cwd = root).out.trim() expect(output == "Hello default WASM!") @@ -394,7 +394,7 @@ trait RunScalaJsTestDefinitions { this: RunTestDefinitions => } } - test("WASM passes arguments to program") { + test("Wasm passes arguments to program") { // Scala.js always passes an empty Array[String] to main(args), // so we must read process.argv directly via JS interop. val inputs = TestInputs( @@ -415,8 +415,8 @@ trait RunScalaJsTestDefinitions { this: RunTestDefinitions => "--power", "run", "Hello.scala", - "--wasm", - "--wasm-runtime", + "--js-emit-wasm", + "--js-wasm-runtime", "node", extraOptions, "--", @@ -429,7 +429,7 @@ trait RunScalaJsTestDefinitions { this: RunTestDefinitions => } if (TestUtil.fromPath("deno").isDefined) - test("Run with --wasm-runtime deno") { + test("Run with --js-wasm-runtime deno") { val inputs = TestInputs( os.rel / "Hello.scala" -> """object Hello { @@ -443,8 +443,8 @@ trait RunScalaJsTestDefinitions { this: RunTestDefinitions => "--power", "run", "Hello.scala", - "--wasm", - "--wasm-runtime", + "--js-emit-wasm", + "--js-wasm-runtime", "deno", extraOptions ).call(cwd = root).out.trim() @@ -453,7 +453,7 @@ trait RunScalaJsTestDefinitions { this: RunTestDefinitions => } if (TestUtil.fromPath("bun").isDefined) - test("Run with --wasm-runtime bun") { + test("Run with --js-wasm-runtime bun") { val inputs = TestInputs( os.rel / "Hello.scala" -> """object Hello { @@ -467,8 +467,8 @@ trait RunScalaJsTestDefinitions { this: RunTestDefinitions => "--power", "run", "Hello.scala", - "--wasm", - "--wasm-runtime", + "--js-emit-wasm", + "--js-wasm-runtime", "bun", extraOptions ).call(cwd = root).out.trim() @@ -476,7 +476,7 @@ trait RunScalaJsTestDefinitions { this: RunTestDefinitions => } } - test("WASM multiple source files") { + test("Wasm multiple source files") { val inputs = TestInputs( os.rel / "Greeter.scala" -> """trait Greeter { @@ -502,8 +502,8 @@ trait RunScalaJsTestDefinitions { this: RunTestDefinitions => "run", "Main.scala", "Greeter.scala", - "--wasm", - "--wasm-runtime", + "--js-emit-wasm", + "--js-wasm-runtime", "node", extraOptions ).call(cwd = root).out.trim() @@ -511,7 +511,7 @@ trait RunScalaJsTestDefinitions { this: RunTestDefinitions => } } - test("WASM exception handling") { + test("Wasm exception handling") { val inputs = TestInputs( os.rel / "Hello.scala" -> """object Hello { @@ -534,8 +534,8 @@ trait RunScalaJsTestDefinitions { this: RunTestDefinitions => "--power", "run", "Hello.scala", - "--wasm", - "--wasm-runtime", + "--js-emit-wasm", + "--js-wasm-runtime", "node", extraOptions ).call(cwd = root).out.trim() @@ -545,7 +545,7 @@ trait RunScalaJsTestDefinitions { this: RunTestDefinitions => } } - test("WASM collections and higher-order functions") { + test("Wasm collections and higher-order functions") { val inputs = TestInputs( os.rel / "Hello.scala" -> """object Hello { @@ -566,8 +566,8 @@ trait RunScalaJsTestDefinitions { this: RunTestDefinitions => "--power", "run", "Hello.scala", - "--wasm", - "--wasm-runtime", + "--js-emit-wasm", + "--js-wasm-runtime", "node", extraOptions ).call(cwd = root).out.trim() @@ -579,7 +579,7 @@ trait RunScalaJsTestDefinitions { this: RunTestDefinitions => } if (!actualScalaVersion.startsWith("2")) - test("WASM @main annotation (Scala 3)") { + test("Wasm @main annotation (Scala 3)") { // Scala.js always passes empty args to main, so @main with parameters won't work. // Test @main without parameters instead. val inputs = TestInputs( @@ -594,8 +594,8 @@ trait RunScalaJsTestDefinitions { this: RunTestDefinitions => "--power", "run", "Hello.scala", - "--wasm", - "--wasm-runtime", + "--js-emit-wasm", + "--js-wasm-runtime", "node", extraOptions ).call(cwd = root).out.trim() diff --git a/modules/options/src/main/scala/scala/build/options/BuildOptions.scala b/modules/options/src/main/scala/scala/build/options/BuildOptions.scala index 9bc4a8b006..f0f09bf26b 100644 --- a/modules/options/src/main/scala/scala/build/options/BuildOptions.scala +++ b/modules/options/src/main/scala/scala/build/options/BuildOptions.scala @@ -37,7 +37,6 @@ final case class BuildOptions( scalaOptions: ScalaOptions = ScalaOptions(), scalaJsOptions: ScalaJsOptions = ScalaJsOptions(), scalaNativeOptions: ScalaNativeOptions = ScalaNativeOptions(), - wasmOptions: WasmOptions = WasmOptions(), internalDependencies: InternalDependenciesOptions = InternalDependenciesOptions(), javaOptions: JavaOptions = JavaOptions(), jmhOptions: JmhOptions = JmhOptions(), diff --git a/modules/options/src/main/scala/scala/build/options/ScalaJsOptions.scala b/modules/options/src/main/scala/scala/build/options/ScalaJsOptions.scala index ccaef26c33..b4830acfd1 100644 --- a/modules/options/src/main/scala/scala/build/options/ScalaJsOptions.scala +++ b/modules/options/src/main/scala/scala/build/options/ScalaJsOptions.scala @@ -26,7 +26,8 @@ final case class ScalaJsOptions( smallModuleForPackage: List[String] = Nil, esVersionStr: Option[String] = None, noOpt: Option[Boolean] = None, - jsEmitWasm: Boolean = false + jsEmitWasm: Boolean = false, + wasmRuntime: WasmRuntime = WasmRuntime.default ) { def fullOpt: Either[UnrecognizedJsOptModeError, Boolean] = if (mode.isValid) @@ -155,7 +156,8 @@ final case class ScalaJsOptions( ) ScalaJsLinkerConfig( - moduleKind = moduleKind(logger), + moduleKind = + if (jsEmitWasm) ScalaJsLinkerConfig.ModuleKind.ESModule else moduleKind(logger), checkIR = checkIr.getOrElse(false), // meh sourceMap = emitSourceMaps, moduleSplitStyle = moduleSplitStyle(logger), diff --git a/modules/options/src/main/scala/scala/build/options/WasmOptions.scala b/modules/options/src/main/scala/scala/build/options/WasmOptions.scala deleted file mode 100644 index 34450e2385..0000000000 --- a/modules/options/src/main/scala/scala/build/options/WasmOptions.scala +++ /dev/null @@ -1,18 +0,0 @@ -package scala.build.options - -/** Options for WebAssembly compilation and execution. - * - * @param enabled - * If true, enable WASM output (Scala.js WASM backend) - * @param runtime - * The WASM runtime to use for execution (node, deno) - */ -final case class WasmOptions( - enabled: Boolean = false, - runtime: WasmRuntime = WasmRuntime.default -) - -object WasmOptions { - implicit val hasHashData: HasHashData[WasmOptions] = HasHashData.derive - implicit val monoid: ConfigMonoid[WasmOptions] = ConfigMonoid.derive -} diff --git a/modules/options/src/main/scala/scala/build/options/WasmRuntime.scala b/modules/options/src/main/scala/scala/build/options/WasmRuntime.scala index b5f8814e5d..5afae2d49f 100644 --- a/modules/options/src/main/scala/scala/build/options/WasmRuntime.scala +++ b/modules/options/src/main/scala/scala/build/options/WasmRuntime.scala @@ -4,7 +4,7 @@ import java.util.Locale /** Represents available WebAssembly runtimes for execution. * - * JS-based runtimes (work now with Scala.js WASM backend): + * JS-based runtimes (work now with Scala.js Wasm backend): * - Node: Uses Node.js (V8 engine) with JavaScript loader * - Deno: Uses Deno (V8 engine) with ES module support * - Bun: Uses Bun (JavaScriptCore engine) with ES module support diff --git a/website/docs/reference/cli-options.md b/website/docs/reference/cli-options.md index 5384fdf679..b462cbc84d 100644 --- a/website/docs/reference/cli-options.md +++ b/website/docs/reference/cli-options.md @@ -1379,7 +1379,11 @@ Enable jsdom ### `--js-emit-wasm` -Emit WASM +Enable Wasm output (Scala.js Wasm backend). Uses Node.js by default. To show more options for Wasm pass `--help-wasm` + +### `--js-wasm-runtime` + +Wasm runtime to use: node (default), deno, bun ### `--js-header` @@ -1972,22 +1976,6 @@ A github token used to access GitHub. Not needed in most cases. Don't check for the newest available Scala CLI version upstream -## Wasm options - -Available in commands: - -[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`dependency-update`](./commands.md#dependency-update), [`doc`](./commands.md#doc), [`export`](./commands.md#export), [`fix`](./commands.md#fix), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`package`](./commands.md#package), [`publish`](./commands.md#publish), [`publish local`](./commands.md#publish-local), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) - - - -### `--wasm` - -Enable WebAssembly output (Scala.js WASM backend). Uses Node.js by default. To show more options for WASM pass `--help-wasm` - -### `--wasm-runtime` - -WASM runtime to use: node (default), deno, bun - ## Watch options Available in commands: diff --git a/website/docs/reference/commands.md b/website/docs/reference/commands.md index 643f0cd72e..9aaeff82ed 100644 --- a/website/docs/reference/commands.md +++ b/website/docs/reference/commands.md @@ -32,7 +32,7 @@ All supported types of inputs can be mixed with each other. For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/compile -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [compile](./cli-options.md#compile-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [compile](./cli-options.md#compile-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ## config @@ -83,7 +83,7 @@ Accepts option groups: [config](./cli-options.md#config-options), [coursier](./c Update dependency directives in the project -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [dependency update](./cli-options.md#dependency-update-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [dependency update](./cli-options.md#dependency-update-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [workspace](./cli-options.md#workspace-options) ## doc @@ -97,7 +97,7 @@ All supported types of inputs can be mixed with each other. For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/doc -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [doc](./cli-options.md#doc-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [doc](./cli-options.md#doc-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [workspace](./cli-options.md#workspace-options) ## export @@ -119,7 +119,7 @@ The `export` sub-command is experimental. Please bear in mind that non-ideal user experience should be expected. If you encounter any bugs or have feedback to share, make sure to reach out to the maintenance team at https://github.com/VirtusLab/scala-cli -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [export](./cli-options.md#export-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [export](./cli-options.md#export-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [workspace](./cli-options.md#workspace-options) ## fix @@ -145,7 +145,7 @@ The `fix` sub-command is experimental. Please bear in mind that non-ideal user experience should be expected. If you encounter any bugs or have feedback to share, make sure to reach out to the maintenance team at https://github.com/VirtusLab/scala-cli -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [fix](./cli-options.md#fix-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [Scalafix](./cli-options.md#scalafix-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [fix](./cli-options.md#fix-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [Scalafix](./cli-options.md#scalafix-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [workspace](./cli-options.md#workspace-options) ## fmt @@ -162,7 +162,7 @@ All standard Scala CLI inputs are accepted, but only Scala sources will be forma For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/fmt -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [fmt](./cli-options.md#fmt-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [fmt](./cli-options.md#fmt-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [workspace](./cli-options.md#workspace-options) ## help @@ -214,7 +214,7 @@ All supported types of inputs can be mixed with each other. For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/repl -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [repl](./cli-options.md#repl-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [repl](./cli-options.md#repl-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ## package @@ -232,7 +232,7 @@ All supported types of inputs can be mixed with each other. For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/package -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [package](./cli-options.md#package-options), [packager](./cli-options.md#packager-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [package](./cli-options.md#package-options), [packager](./cli-options.md#packager-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ## publish @@ -259,7 +259,7 @@ The `publish` sub-command is experimental. Please bear in mind that non-ideal user experience should be expected. If you encounter any bugs or have feedback to share, make sure to reach out to the maintenance team at https://github.com/VirtusLab/scala-cli -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [pgp scala signing](./cli-options.md#pgp-scala-signing-options), [power](./cli-options.md#power-options), [publish](./cli-options.md#publish-options), [publish connection](./cli-options.md#publish-connection-options), [publish params](./cli-options.md#publish-params-options), [publish repository](./cli-options.md#publish-repository-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [pgp scala signing](./cli-options.md#pgp-scala-signing-options), [power](./cli-options.md#power-options), [publish](./cli-options.md#publish-options), [publish connection](./cli-options.md#publish-connection-options), [publish params](./cli-options.md#publish-params-options), [publish repository](./cli-options.md#publish-repository-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ## publish local @@ -271,7 +271,7 @@ The `publish-local` sub-command is experimental. Please bear in mind that non-ideal user experience should be expected. If you encounter any bugs or have feedback to share, make sure to reach out to the maintenance team at https://github.com/VirtusLab/scala-cli -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [pgp scala signing](./cli-options.md#pgp-scala-signing-options), [power](./cli-options.md#power-options), [publish](./cli-options.md#publish-options), [publish local](./cli-options.md#publish-local-options), [publish params](./cli-options.md#publish-params-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [pgp scala signing](./cli-options.md#pgp-scala-signing-options), [power](./cli-options.md#power-options), [publish](./cli-options.md#publish-options), [publish local](./cli-options.md#publish-local-options), [publish params](./cli-options.md#publish-params-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ## publish setup @@ -309,7 +309,7 @@ To pass arguments to the actual application, just add them after `--`, like: For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/run -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [run](./cli-options.md#run-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [run](./cli-options.md#run-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ## github secret create @@ -356,7 +356,7 @@ Using directives can be defined in all supported input source file types. For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/setup-ide -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [bsp file](./cli-options.md#bsp-file-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [setup IDE](./cli-options.md#setup-ide-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [bsp file](./cli-options.md#bsp-file-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [setup IDE](./cli-options.md#setup-ide-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [workspace](./cli-options.md#workspace-options) ## shebang @@ -387,7 +387,7 @@ Using this, it is possible to conveniently set up Unix shebang scripts. For exam For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/shebang -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [run](./cli-options.md#run-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [run](./cli-options.md#run-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ## test @@ -411,7 +411,7 @@ All supported types of inputs can be mixed with each other. For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/test -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [test](./cli-options.md#test-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [test](./cli-options.md#test-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ## uninstall @@ -514,7 +514,7 @@ It is normally supposed to be invoked by your IDE when a Scala CLI project is im Detailed documentation can be found on our website: https://scala-cli.virtuslab.org -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [bsp](./cli-options.md#bsp-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [bsp](./cli-options.md#bsp-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [workspace](./cli-options.md#workspace-options) ### default-file diff --git a/website/docs/reference/directives.md b/website/docs/reference/directives.md index d9640d57bf..02dfb2f135 100644 --- a/website/docs/reference/directives.md +++ b/website/docs/reference/directives.md @@ -707,7 +707,7 @@ Use a toolkit as dependency (not supported in Scala 2.12), 'default' version for `//> using test.toolkit default` -### WASM options +### Wasm options Add WebAssembly options diff --git a/website/docs/reference/scala-command/cli-options.md b/website/docs/reference/scala-command/cli-options.md index bd8ebaf16a..91916db057 100644 --- a/website/docs/reference/scala-command/cli-options.md +++ b/website/docs/reference/scala-command/cli-options.md @@ -1495,16 +1495,6 @@ A github token used to access GitHub. Not needed in most cases. Don't check for the newest available Scala CLI version upstream -## Wasm options - -Available in commands: - -[`bsp`](./commands.md#bsp), [`compile`](./commands.md#compile), [`doc`](./commands.md#doc), [`fmt` , `format` , `scalafmt`](./commands.md#fmt), [`repl` , `console`](./commands.md#repl), [`run`](./commands.md#run), [`setup-ide`](./commands.md#setup-ide), [`shebang`](./commands.md#shebang), [`test`](./commands.md#test) - - - -*This section was automatically generated and may be empty if no options were available.* - ## Watch options Available in commands: diff --git a/website/docs/reference/scala-command/commands.md b/website/docs/reference/scala-command/commands.md index e7fbd71e5a..8b7c42a9eb 100644 --- a/website/docs/reference/scala-command/commands.md +++ b/website/docs/reference/scala-command/commands.md @@ -31,7 +31,7 @@ All supported types of inputs can be mixed with each other. For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/compile -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [compile](./cli-options.md#compile-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [compile](./cli-options.md#compile-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ### config @@ -90,7 +90,7 @@ All supported types of inputs can be mixed with each other. For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/doc -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [doc](./cli-options.md#doc-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [doc](./cli-options.md#doc-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [workspace](./cli-options.md#workspace-options) ### repl @@ -112,7 +112,7 @@ All supported types of inputs can be mixed with each other. For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/repl -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [repl](./cli-options.md#repl-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [repl](./cli-options.md#repl-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ### run @@ -138,7 +138,7 @@ To pass arguments to the actual application, just add them after `--`, like: For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/run -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [run](./cli-options.md#run-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [run](./cli-options.md#run-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ### shebang @@ -169,7 +169,7 @@ Using this, it is possible to conveniently set up Unix shebang scripts. For exam For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/shebang -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [run](./cli-options.md#run-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [main class](./cli-options.md#main-class-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [run](./cli-options.md#run-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ## SHOULD have commands: @@ -188,7 +188,7 @@ All standard Scala CLI inputs are accepted, but only Scala sources will be forma For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/fmt -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [fmt](./cli-options.md#fmt-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [fmt](./cli-options.md#fmt-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [workspace](./cli-options.md#workspace-options) ### test @@ -212,7 +212,7 @@ All supported types of inputs can be mixed with each other. For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/test -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [test](./cli-options.md#test-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [cross](./cli-options.md#cross-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [java](./cli-options.md#java-options), [java prop](./cli-options.md#java-prop-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [test](./cli-options.md#test-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [watch](./cli-options.md#watch-options), [workspace](./cli-options.md#workspace-options) ### version @@ -244,7 +244,7 @@ It is normally supposed to be invoked by your IDE when a Scala CLI project is im Detailed documentation can be found on our website: https://scala-cli.virtuslab.org -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [bsp](./cli-options.md#bsp-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [bsp](./cli-options.md#bsp-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [workspace](./cli-options.md#workspace-options) ### clean @@ -296,7 +296,7 @@ Using directives can be defined in all supported input source file types. For detailed documentation refer to our website: https://scala-cli.virtuslab.org/docs/commands/setup-ide -Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [bsp file](./cli-options.md#bsp-file-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [setup IDE](./cli-options.md#setup-ide-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [wasm](./cli-options.md#wasm-options), [workspace](./cli-options.md#workspace-options) +Accepts option groups: [benchmarking](./cli-options.md#benchmarking-options), [bsp file](./cli-options.md#bsp-file-options), [compilation server](./cli-options.md#compilation-server-options), [coursier](./cli-options.md#coursier-options), [debug](./cli-options.md#debug-options), [dependency](./cli-options.md#dependency-options), [global suppress warning](./cli-options.md#global-suppress-warning-options), [help group](./cli-options.md#help-group-options), [input](./cli-options.md#input-options), [jvm](./cli-options.md#jvm-options), [logging](./cli-options.md#logging-options), [markdown](./cli-options.md#markdown-options), [power](./cli-options.md#power-options), [python](./cli-options.md#python-options), [Scala.js](./cli-options.md#scalajs-options), [Scala Native](./cli-options.md#scala-native-options), [scalac](./cli-options.md#scalac-options), [scalac extra](./cli-options.md#scalac-extra-options), [scope](./cli-options.md#scope-options), [semantic db](./cli-options.md#semantic-db-options), [setup IDE](./cli-options.md#setup-ide-options), [shared](./cli-options.md#shared-options), [snippet](./cli-options.md#snippet-options), [source generator](./cli-options.md#source-generator-options), [suppress warning](./cli-options.md#suppress-warning-options), [verbosity](./cli-options.md#verbosity-options), [version](./cli-options.md#version-options), [workspace](./cli-options.md#workspace-options) ### uninstall From 7899c1eb83ae0f4e593ba40135cb60feb902d425 Mon Sep 17 00:00:00 2001 From: lostflydev Date: Sat, 30 May 2026 12:28:26 +0300 Subject: [PATCH 6/8] Add logging for implicit Wasm behaviors; rebase on upstream main - Log when --experimental-wasm-exnref is injected in runJs (Node.js < 25) - Log when Wasm mode enables ES module output in Run.scala - Improve comment in Wasm.scala directive to reference AmbiguousPlatformError for --wasm + --platform native conflict detection --- .../build/src/main/scala/scala/build/internal/Runner.scala | 4 ++++ modules/cli/src/main/scala/scala/cli/commands/run/Run.scala | 1 + .../scala/scala/build/preprocessing/directives/Wasm.scala | 3 ++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/modules/build/src/main/scala/scala/build/internal/Runner.scala b/modules/build/src/main/scala/scala/build/internal/Runner.scala index d5c4d7585c..16367efab4 100644 --- a/modules/build/src/main/scala/scala/build/internal/Runner.scala +++ b/modules/build/src/main/scala/scala/build/internal/Runner.scala @@ -283,6 +283,10 @@ object Runner { .map(_.toString) .toRight(NodeNotFoundError())) val nodeFlags = if (emitWasm && nodeNeedsWasmFlag) List("--experimental-wasm-exnref") else Nil + if (emitWasm && nodeFlags.nonEmpty) + logger.log( + s"Wasm: adding ${nodeFlags.mkString(" ")} (required for Wasm exception handling on Node.js < 25)" + ) if !jsDom && allowExecve && Execve.available() then { val command = Seq(nodePath) ++ nodeFlags ++ Seq(entrypoint.getAbsolutePath) ++ args diff --git a/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala b/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala index 0a4467ee86..8e17ab0762 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala @@ -480,6 +480,7 @@ object Run extends ScalaCommand[RunOptions] with BuildCommandHelpers { if jsOpts.jsEmitWasm then { val runtime = jsOpts.wasmRuntime val esModule = true // Wasm backend uses ES modules + logger.log("Wasm mode enabled: using ES module output on JS platform") scratchDirOpt.foreach(os.makeDir.all(_)) val jsDest = os.temp( dir = scratchDirOpt.orNull, diff --git a/modules/directives/src/main/scala/scala/build/preprocessing/directives/Wasm.scala b/modules/directives/src/main/scala/scala/build/preprocessing/directives/Wasm.scala index 932fafee89..e465f799cc 100644 --- a/modules/directives/src/main/scala/scala/build/preprocessing/directives/Wasm.scala +++ b/modules/directives/src/main/scala/scala/build/preprocessing/directives/Wasm.scala @@ -37,7 +37,8 @@ final case class Wasm( } parsedRuntime.map { runtime => val wasmEnabled = wasm.getOrElse(false) || wasmRuntime.isDefined - // When Wasm is enabled, force Platform.JS (Scala.js Wasm backend requires JS compilation) + // Scala.js Wasm backend requires JS platform. When --platform native is also + // specified alongside --wasm, an AmbiguousPlatformError is raised in platform resolution. val scalaOptions = if (wasmEnabled) ScalaOptions(platform = Some(Positioned.none(Platform.JS))) From b40d2e9a283a07e017469dac08e78b4fceab71dc Mon Sep 17 00:00:00 2001 From: lostflydev Date: Sat, 30 May 2026 13:33:55 +0300 Subject: [PATCH 7/8] Fix DENO_V8_FLAGS override and add warning for --js-module-kind + Wasm - runDeno: append --experimental-wasm-exnref to existing DENO_V8_FLAGS instead of silently replacing user-defined flags; log when flag is set - ScalaJsOptions.linkerConfig: warn when Wasm overrides user-specified --js-module-kind (forced to ESModule by Wasm backend) --- .../main/scala/scala/build/internal/Runner.scala | 13 +++++++++++-- .../scala/scala/build/options/ScalaJsOptions.scala | 4 ++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/modules/build/src/main/scala/scala/build/internal/Runner.scala b/modules/build/src/main/scala/scala/build/internal/Runner.scala index 16367efab4..b524ac705f 100644 --- a/modules/build/src/main/scala/scala/build/internal/Runner.scala +++ b/modules/build/src/main/scala/scala/build/internal/Runner.scala @@ -367,9 +367,18 @@ object Runner { .map(_.toString) .toRight(DenoNotFoundError())) val denoFlags = Seq("run", "--allow-read") + val wasmFlag = "--experimental-wasm-exnref" val extraEnv = - if (emitWasm && denoNeedsWasmFlag) Map("DENO_V8_FLAGS" -> "--experimental-wasm-exnref") - else Map.empty + if (emitWasm && denoNeedsWasmFlag) { + // Append to any existing DENO_V8_FLAGS rather than replacing them. + val existing = sys.env.get("DENO_V8_FLAGS").filter(_.nonEmpty) + val merged = existing.fold(wasmFlag)(f => s"$f $wasmFlag") + logger.log( + s"Wasm: setting DENO_V8_FLAGS=$merged (required for Wasm exception handling)" + ) + Map("DENO_V8_FLAGS" -> merged) + } + else Map.empty[String, String] if (allowExecve && Execve.available()) { val command = Seq(denoPath) ++ denoFlags ++ Seq(entrypoint.getAbsolutePath) ++ args diff --git a/modules/options/src/main/scala/scala/build/options/ScalaJsOptions.scala b/modules/options/src/main/scala/scala/build/options/ScalaJsOptions.scala index b4830acfd1..f162de8526 100644 --- a/modules/options/src/main/scala/scala/build/options/ScalaJsOptions.scala +++ b/modules/options/src/main/scala/scala/build/options/ScalaJsOptions.scala @@ -155,6 +155,10 @@ final case class ScalaJsOptions( esVersion = esVersion(logger) ) + if (jsEmitWasm && moduleKindStr.isDefined) + logger.message( + s"[${Console.YELLOW}warn${Console.RESET}] Wasm mode forces ES module output; --js-module-kind is ignored" + ) ScalaJsLinkerConfig( moduleKind = if (jsEmitWasm) ScalaJsLinkerConfig.ModuleKind.ESModule else moduleKind(logger), From 2c5eebbfb056e26e49b5e26e0703ee9e79a20add Mon Sep 17 00:00:00 2001 From: lostflydev Date: Sun, 31 May 2026 11:58:37 +0300 Subject: [PATCH 8/8] Restore SbtFile and null guards in JVM sourceFiles match Lost during Run.scala restructure for Wasm: restores the original case _: SbtFile => "" and case null => "" branches so SbtFile inputs are properly filtered from scala.sources JVM property. --- modules/cli/src/main/scala/scala/cli/commands/run/Run.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala b/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala index 8e17ab0762..b4ba60a090 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala @@ -677,8 +677,9 @@ object Run extends ScalaCommand[RunOptions] with BuildCommandHelpers { case s: ScalaFile => fwd(s.path.toString) case s: Script => fwd(s.path.toString) case s: MarkdownFile => fwd(s.path.toString) + case _: SbtFile => "" case s: OnDisk => fwd(s.path.toString) - case s => s.getClass.getName + case null => "" }.filter(_.nonEmpty).distinct val sources = sourceFiles.mkString(File.pathSeparator) val sourceNames = sourceFiles.map(base).mkString(File.pathSeparator)