From d5139c175b6b2254ff65c14ee59a37750d3bcd34 Mon Sep 17 00:00:00 2001 From: Wojciech Decker Date: Wed, 16 Jun 2021 16:23:57 +0200 Subject: [PATCH] Support Scala.js 1.5.0 --- .github/workflows/ci.yml | 2 +- appveyor.yml | 2 +- build.sbt | 13 ++- scripts/test-cli.sh | 17 ++- .../scala/org/scalajs/cli/Scalajsld.scala | 100 ++++++++++++++---- 5 files changed, 108 insertions(+), 26 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f021a4c..b06b115 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ jobs: fail-fast: false matrix: scalaversion: ["2.11.12", "2.12.10", "2.13.1"] - scalajsversion: ["1.0.0"] + scalajsversion: ["1.5.0"] steps: - uses: actions/checkout@v2 - uses: olafurpg/setup-scala@v10 diff --git a/appveyor.yml b/appveyor.yml index c4d914d..fb11265 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,7 +2,7 @@ version: '{build}' os: Windows Server 2012 environment: global: - SCALAJS_VERSION: 1.0.0 + SCALAJS_VERSION: 1.5.0 matrix: - SCALA_VERSION: 2.11.12 - SCALA_VERSION: 2.12.10 diff --git a/build.sbt b/build.sbt index 60eab05..67e9648 100644 --- a/build.sbt +++ b/build.sbt @@ -11,14 +11,14 @@ val cliPack = taskKey[File]("Pack the CLI for the current configuration") inThisBuild(Def.settings( - version := "1.0.1-SNAPSHOT", + version := "1.5.0-SNAPSHOT", organization := "org.scala-js", - crossScalaVersions := Seq("2.12.10", "2.11.12", "2.13.1"), + crossScalaVersions := Seq("2.12.13", "2.11.12", "2.13.5"), scalaVersion := crossScalaVersions.value.head, scalacOptions ++= Seq("-deprecation", "-feature", "-Xfatal-warnings"), - scalaJSVersion := "1.0.0", + scalaJSVersion := "1.5.0", scalaJSScalaVersions := Seq( "2.11.12", @@ -32,8 +32,15 @@ inThisBuild(Def.settings( "2.12.8", "2.12.9", "2.12.10", + "2.12.11", + "2.12.12", + "2.12.13", "2.13.0", "2.13.1", + "2.13.2", + "2.13.3", + "2.13.4", + "2.13.5", ), homepage := Some(url("https://www.scala-js.org/")), diff --git a/scripts/test-cli.sh b/scripts/test-cli.sh index 0fcd920..6aba87a 100755 --- a/scripts/test-cli.sh +++ b/scripts/test-cli.sh @@ -48,11 +48,24 @@ test -s out || fail "scalajsp bin/Foo$.sjsir: empty output" scalajsp bin/Foo\$A.sjsir > out test -s out || fail "scalajsp bin/Foo\$A.sjsir: empty output" -scalajsld -s -o test.js -mm Foo.main bin +scalajsld -s -o test.js -mm Foo.main bin 2> test_stderr.txt +grep -Fxq "Warning: using a single file as output (--output) is deprecated since Scala.js 1.3.0. Use --outputDir instead." test_stderr.txt \ + || fail "expected warning. Got: $(cat test_stderr.txt)" test -s test.js || fail "scalajsld: empty output" test -s test.js.map || fail "scalajsld: empty source map" -node test.js > got.run +node test.js > got-legacy.run +cat > want-legacy.run < got.run cat > want.run < + All.find(_.toString() == s).getOrElse( + throw new IllegalArgumentException(s"$s is not a valid module split style")) + } + } + def main(args: Array[String]): Unit = { val parser = new scopt.OptionParser[Options]("scalajsld") { head("scalajsld", ScalaJSVersions.current) @@ -81,15 +93,26 @@ object Scalajsld { .text("Execute the specified main(Array[String]) method on startup") opt[File]('o', "output") .valueName("") - .required() - .action { (x, c) => c.copy(output = x) } - .text("Output file of linker (required)") + .action { (x, c) => c.copy(output = Some(x)) } + .text("Output file of linker (deprecated)") + opt[File]('z', "outputDir") + .valueName("") + .action { (x, c) => c.copy(outputDir = Some(x)) } + .text("Output directory of linker (required)") opt[Unit]('f', "fastOpt") .action { (_, c) => c.copy(noOpt = false, fullOpt = false) } .text("Optimize code (this is the default)") opt[Unit]('n', "noOpt") .action { (_, c) => c.copy(noOpt = true, fullOpt = false) } .text("Don't optimize code") + opt[ModuleSplitStyle]("moduleSplitStyle") + .action { (x, c) => c.copy(moduleSplitStyle = x) } + .text("Module splitting style " + ModuleSplitStyleRead.All.mkString("(", ", ", ")")) + opt[String]("jsFilePattern") + .action { (x, c) => c.copy(outputPatterns = OutputPatterns.fromJSFile(x)) } + .text("Pattern for JS file names (default: `%s.js`). " + + "Expects a printf-style pattern with a single placeholder for the module ID. " + + "A typical use case is changing the file extension, e.g. `%.mjs` for Node.js modules.") opt[Unit]('u', "fullOpt") .action { (_, c) => c.copy(noOpt = false, fullOpt = true) } .text("Fully optimize code (uses Google Closure Compiler)") @@ -143,6 +166,17 @@ object Scalajsld { help("help") .abbr("h") .text("prints this usage text") + checkConfig { c => + if (c.output.isDefined) { + reportWarning("using a single file as output (--output) is deprecated since Scala.js 1.3.0." + + " Use --outputDir instead.") + } + + if (c.outputDir.isDefined == c.output.isDefined) + failure("exactly one of --output or --outputDir have to be defined") + else + success + } override def showUsageOnError = true } @@ -158,6 +192,8 @@ object Scalajsld { val config = StandardConfig() .withSemantics(semantics) .withModuleKind(options.moduleKind) + .withModuleSplitStyle(options.moduleSplitStyle) + .withOutputPatterns(options.outputPatterns) .withESFeatures(options.esFeatures) .withCheckIR(options.checkIR) .withOptimizer(!options.noOpt) @@ -170,27 +206,53 @@ object Scalajsld { val linker = StandardImpl.linker(config) val logger = new ScalaConsoleLogger(options.logLevel) - - val output = { - val js = options.output.toPath() - val sm = js.resolveSibling(js.getFileName().toString() + ".map") - - def relURI(f: Path) = - new URI(null, null, f.getFileName().toString, null) - - LinkerOutput(PathOutputFile(js)) - .withSourceMap(PathOutputFile(sm)) - .withSourceMapURI(relURI(sm)) - .withJSFileURI(relURI(js)) - } - val cache = StandardImpl.irFileCache().newCache val result = PathIRContainer .fromClasspath(classpath) .flatMap(containers => cache.cached(containers._1)) - .flatMap(linker.link(_, moduleInitializers, output, logger)) + .flatMap { irFiles => + (options.output, options.outputDir) match { + case (Some(jsFile), None) => + (DeprecatedLinkerAPI: DeprecatedLinkerAPI).link(linker, irFiles.toList, moduleInitializers, jsFile, logger) + case (None, Some(outputDir)) => + linker.link(irFiles, moduleInitializers, PathOutputDirectory(outputDir.toPath()), logger) + case _ => throw new AssertionError("Either output or outputDir have to be defined.") + } + } Await.result(result, Duration.Inf) } } + + // Covers deprecated api with not deprecated method. Suppresses warning. + private abstract class DeprecatedLinkerAPI { + def link(linker: Linker, + irFiles: Seq[IRFile], + moduleInitializers: Seq[ModuleInitializer], + linkerOutputFile: File, + logger: Logger): Future[Unit] + } + + private object DeprecatedLinkerAPI extends DeprecatedLinkerAPI { + def apply(): DeprecatedLinkerAPI = this + + @deprecated("Deprecate to silence warnings", "never/always") + def link(linker: Linker, + irFiles: Seq[IRFile], + moduleInitializers: Seq[ModuleInitializer], + linkerOutputFile: File, + logger: Logger): Future[Unit] = { + val js = linkerOutputFile.toPath() + val sm = js.resolveSibling(js.getFileName().toString() + ".map") + + def relURI(f: Path) = + new URI(null, null, f.getFileName().toString(), null) + + val output = LinkerOutput(PathOutputFile(js)) + .withSourceMap(PathOutputFile(sm)) + .withSourceMapURI(relURI(sm)) + .withJSFileURI(relURI(js)) + linker.link(irFiles, moduleInitializers, output, logger) + } + } }