diff --git a/build.sc b/build.sc index de511ddf174..0487de1ee61 100755 --- a/build.sc +++ b/build.sc @@ -12,17 +12,17 @@ import mill.modules.Jvm.createAssembly object Deps { object Scalajs_0_6 { - val scalajsJsEnvs = ivy"org.scala-js::scalajs-js-envs:0.6.32" - val scalajsSbtTestAdapter = ivy"org.scala-js::scalajs-sbt-test-adapter:0.6.32" - val scalajsTools = ivy"org.scala-js::scalajs-tools:0.6.32" + val scalajsJsEnvs = ivy"org.scala-js::scalajs-js-envs:0.6.33" + val scalajsSbtTestAdapter = ivy"org.scala-js::scalajs-sbt-test-adapter:0.6.33" + val scalajsTools = ivy"org.scala-js::scalajs-tools:0.6.33" } object Scalajs_1 { val scalajsEnvJsdomNodejs = ivy"org.scala-js::scalajs-env-jsdom-nodejs:1.1.0" val scalajsEnvNodejs = ivy"org.scala-js::scalajs-env-nodejs:1.1.1" val scalajsEnvPhantomjs = ivy"org.scala-js::scalajs-env-phantomjs:1.0.0" - val scalajsSbtTestAdapter = ivy"org.scala-js::scalajs-sbt-test-adapter:1.1.1" - val scalajsLinker = ivy"org.scala-js::scalajs-linker:1.1.1" + val scalajsSbtTestAdapter = ivy"org.scala-js::scalajs-sbt-test-adapter:1.3.1" + val scalajsLinker = ivy"org.scala-js::scalajs-linker:1.3.1" } object Scalanative_0_3 { diff --git a/scalajslib/api/src/ScalaJSWorkerApi.scala b/scalajslib/api/src/ScalaJSWorkerApi.scala index 21130cf5f17..57bfe67012c 100644 --- a/scalajslib/api/src/ScalaJSWorkerApi.scala +++ b/scalajslib/api/src/ScalaJSWorkerApi.scala @@ -8,7 +8,8 @@ trait ScalaJSWorkerApi { main: String, testBridgeInit: Boolean, fullOpt: Boolean, - moduleKind: ModuleKind): Result[File] + moduleKind: ModuleKind, + useECMAScript2015: Boolean): Result[File] def run(config: JsEnvConfig, linkedFile: File): Unit @@ -29,6 +30,7 @@ sealed trait ModuleKind object ModuleKind{ object NoModule extends ModuleKind object CommonJSModule extends ModuleKind + object ESModule extends ModuleKind } diff --git a/scalajslib/src/ScalaJSModule.scala b/scalajslib/src/ScalaJSModule.scala index 1b239659d85..508df1e8934 100644 --- a/scalajslib/src/ScalaJSModule.scala +++ b/scalajslib/src/ScalaJSModule.scala @@ -75,7 +75,8 @@ trait ScalaJSModule extends scalalib.ScalaModule { outer => finalMainClassOpt().toOption, testBridgeInit = false, FastOpt, - moduleKind() + moduleKind(), + useECMAScript2015() ) } @@ -87,7 +88,8 @@ trait ScalaJSModule extends scalalib.ScalaModule { outer => finalMainClassOpt().toOption, testBridgeInit = false, FullOpt, - moduleKind() + moduleKind(), + useECMAScript2015() ) } @@ -121,7 +123,8 @@ trait ScalaJSModule extends scalalib.ScalaModule { outer => mainClass: Option[String], testBridgeInit: Boolean, mode: OptimizeMode, - moduleKind: ModuleKind)(implicit ctx: Ctx): Result[PathRef] = { + moduleKind: ModuleKind, + useECMAScript2015: Boolean)(implicit ctx: Ctx): Result[PathRef] = { val outputPath = ctx.dest / "out.js" os.makeDir.all(ctx.dest) @@ -141,7 +144,8 @@ trait ScalaJSModule extends scalalib.ScalaModule { outer => mainClass, testBridgeInit, mode == FullOpt, - moduleKind + moduleKind, + useECMAScript2015 ).map(PathRef(_)) } @@ -167,6 +171,8 @@ trait ScalaJSModule extends scalalib.ScalaModule { outer => def jsEnvConfig: T[JsEnvConfig] = T { JsEnvConfig.NodeJs() } def moduleKind: T[ModuleKind] = T { ModuleKind.NoModule } + + def useECMAScript2015: T[Boolean] = false } trait TestScalaJSModule extends ScalaJSModule with TestModule { @@ -190,7 +196,8 @@ trait TestScalaJSModule extends ScalaJSModule with TestModule { None, testBridgeInit = true, FastOpt, - moduleKind() + moduleKind(), + useECMAScript2015() ) } diff --git a/scalajslib/src/ScalaJSWorkerApi.scala b/scalajslib/src/ScalaJSWorkerApi.scala index a7d9c8c836e..64793667044 100644 --- a/scalajslib/src/ScalaJSWorkerApi.scala +++ b/scalajslib/src/ScalaJSWorkerApi.scala @@ -37,7 +37,8 @@ class ScalaJSWorker { main: Option[String], testBridgeInit: Boolean, fullOpt: Boolean, - moduleKind: ModuleKind) + moduleKind: ModuleKind, + useECMAScript2015: Boolean) (implicit ctx: Ctx.Home): Result[os.Path] = { bridge(toolsClasspath).link( sources.items.map(_.toIO).toArray, @@ -46,7 +47,8 @@ class ScalaJSWorker { main.orNull, testBridgeInit, fullOpt, - moduleKind + moduleKind, + useECMAScript2015 ).map(os.Path(_)) } diff --git a/scalajslib/test/src/HelloJSWorldTests.scala b/scalajslib/test/src/HelloJSWorldTests.scala index 67710970a30..18457d87fb1 100644 --- a/scalajslib/test/src/HelloJSWorldTests.scala +++ b/scalajslib/test/src/HelloJSWorldTests.scala @@ -23,17 +23,18 @@ object HelloJSWorldTests extends TestSuite { } object HelloJSWorld extends TestUtil.BaseModule { - val scalaVersions = Seq("2.13.2", "2.12.11", "2.11.12") - val scalaJSVersions = Seq("1.1.1", "1.0.1", "0.6.33") + val scalaVersions = Seq("2.13.3", "2.12.12", "2.11.12") + val scalaJSVersionsAndUseECMA2015 = Seq(("1.3.1", false), ("1.3.1", true), ("1.0.1", false), ("0.6.33", false)) val matrix = for { scala <- scalaVersions - scalaJS <- scalaJSVersions - } yield (scala, scalaJS) + (scalaJS, useECMAScript2015) <- scalaJSVersionsAndUseECMA2015 + } yield (scala, scalaJS, useECMAScript2015) object helloJsWorld extends Cross[BuildModule](matrix:_*) - class BuildModule(val crossScalaVersion: String, sjsVersion0: String) extends HelloJSWorldModule { + class BuildModule(val crossScalaVersion: String, sjsVersion0: String, sjsUseECMA2015: Boolean) extends HelloJSWorldModule { override def artifactName = "hello-js-world" def scalaJSVersion = sjsVersion0 + def useECMAScript2015 = sjsUseECMA2015 def pomSettings = PomSettings( organization = "com.lihaoyi", description = "hello js world ready for real world publishing", @@ -47,7 +48,7 @@ object HelloJSWorldTests extends TestSuite { object buildUTest extends Cross[BuildModuleUtest](matrix:_*) class BuildModuleUtest(crossScalaVersion: String, sjsVersion0: String) - extends BuildModule(crossScalaVersion, sjsVersion0) { + extends BuildModule(crossScalaVersion, sjsVersion0, sjsUseECMA2015 = false) { object test extends super.Tests { override def sources = T.sources{ millSourcePath / 'src / 'utest } def testFrameworks = Seq("utest.runner.Framework") @@ -59,7 +60,7 @@ object HelloJSWorldTests extends TestSuite { object buildScalaTest extends Cross[BuildModuleScalaTest](matrix:_*) class BuildModuleScalaTest(crossScalaVersion: String, sjsVersion0: String) - extends BuildModule(crossScalaVersion, sjsVersion0) { + extends BuildModule(crossScalaVersion, sjsVersion0, sjsUseECMA2015 = false) { object test extends super.Tests { override def sources = T.sources{ millSourcePath / 'src / 'scalatest } def testFrameworks = Seq("org.scalatest.tools.Framework") @@ -81,10 +82,9 @@ object HelloJSWorldTests extends TestSuite { def tests: Tests = Tests { prepareWorkspace() 'compile - { - def testCompileFromScratch(scalaVersion: String, - scalaJSVersion: String): Unit = { + def testCompileFromScratch(scalaVersion: String, scalaJSVersion: String, useECMAScript2015: Boolean): Unit = { val Right((result, evalCount)) = - helloWorldEvaluator(HelloJSWorld.helloJsWorld(scalaVersion, scalaJSVersion).compile) + helloWorldEvaluator(HelloJSWorld.helloJsWorld(scalaVersion, scalaJSVersion, useECMAScript2015).compile) val outPath = result.classes.path val outputFiles = os.walk(outPath) @@ -96,24 +96,25 @@ object HelloJSWorldTests extends TestSuite { // don't recompile if nothing changed val Right((_, unchangedEvalCount)) = - helloWorldEvaluator(HelloJSWorld.helloJsWorld(scalaVersion, scalaJSVersion).compile) + helloWorldEvaluator(HelloJSWorld.helloJsWorld(scalaVersion, scalaJSVersion, useECMAScript2015).compile) assert(unchangedEvalCount == 0) } - testAllMatrix((scala, scalaJS) => testCompileFromScratch(scala, scalaJS)) + testAllMatrix((scala, scalaJS, useECMAScript2015) => testCompileFromScratch(scala, scalaJS, useECMAScript2015), skipECMAScript2015 = false) } def testRun(scalaVersion: String, scalaJSVersion: String, + useECMAScript2015: Boolean, mode: OptimizeMode): Unit = { val task = mode match { - case FullOpt => HelloJSWorld.helloJsWorld(scalaVersion, scalaJSVersion).fullOpt - case FastOpt => HelloJSWorld.helloJsWorld(scalaVersion, scalaJSVersion).fastOpt + case FullOpt => HelloJSWorld.helloJsWorld(scalaVersion, scalaJSVersion, useECMAScript2015).fullOpt + case FastOpt => HelloJSWorld.helloJsWorld(scalaVersion, scalaJSVersion, useECMAScript2015).fastOpt } val Right((result, evalCount)) = helloWorldEvaluator(task) val jsFile = result.path val output = ScalaJsUtils.runJS(jsFile) - assert(output == "Hello Scala.js") + assert(output == "Hello Scala.js\n") val sourceMap= jsFile / os.up / (jsFile.last + ".map") assert(sourceMap.toIO.exists()) // sourceMap file was generated assert(os.read(jsFile).contains(s"//# sourceMappingURL=${sourceMap.toNIO.getFileName}")) // jsFile references sourceMap @@ -121,15 +122,15 @@ object HelloJSWorldTests extends TestSuite { } 'fullOpt - { - testAllMatrix((scala, scalaJS) => TestUtil.disableInJava9OrAbove(testRun(scala, scalaJS, FullOpt))) + testAllMatrix((scala, scalaJS, _) => TestUtil.disableInJava9OrAbove(testRun(scala, scalaJS, false, FullOpt))) } 'fastOpt - { - testAllMatrix((scala, scalaJS) => TestUtil.disableInJava9OrAbove(testRun(scala, scalaJS, FastOpt))) + testAllMatrix((scala, scalaJS, useECMAScript2015) => TestUtil.disableInJava9OrAbove(testRun(scala, scalaJS, useECMAScript2015, FastOpt)), skipECMAScript2015 = false) } 'jar - { 'containsSJSIRs - { - val (scala, scalaJS) = HelloJSWorld.matrix.head - val Right((result, evalCount)) = helloWorldEvaluator(HelloJSWorld.helloJsWorld(scala, scalaJS).jar) + val (scala, scalaJS, useECMAScript2015) = HelloJSWorld.matrix.head + val Right((result, evalCount)) = helloWorldEvaluator(HelloJSWorld.helloJsWorld(scala, scalaJS, useECMAScript2015).jar) val jar = result.path val entries = new JarFile(jar.toIO).entries().asScala.map(_.getName) assert(entries.contains("Main$.sjsir")) @@ -139,12 +140,12 @@ object HelloJSWorldTests extends TestSuite { def testArtifactId(scalaVersion: String, scalaJSVersion: String, artifactId: String): Unit = { - val Right((result, evalCount)) = helloWorldEvaluator(HelloJSWorld.helloJsWorld(scalaVersion, scalaJSVersion).artifactMetadata) + val Right((result, evalCount)) = helloWorldEvaluator(HelloJSWorld.helloJsWorld(scalaVersion, scalaJSVersion, false).artifactMetadata) assert(result.id == artifactId) } 'artifactId_06 - testArtifactId(HelloJSWorld.scalaVersions.head, "0.6.33", "hello-js-world_sjs0.6_2.13") 'artifactId_10 - testArtifactId(HelloJSWorld.scalaVersions.head, "1.0.1", "hello-js-world_sjs1_2.13") - 'artifactId_1 - testArtifactId(HelloJSWorld.scalaVersions.head, "1.1.1", "hello-js-world_sjs1_2.13") + 'artifactId_1 - testArtifactId(HelloJSWorld.scalaVersions.head, "1.3.1", "hello-js-world_sjs1_2.13") } def runTests(testTask: define.NamedTask[(String, Seq[TestRunner.Result])]): Map[String, Map[String, TestRunner.Result]] = { @@ -199,18 +200,18 @@ object HelloJSWorldTests extends TestSuite { 'test - { val cached = false - testAllMatrix((scala, scalaJS) => checkUtest(scala, scalaJS, cached), skipScala = _.startsWith("2.11.")) - testAllMatrix((scala, scalaJS) => checkScalaTest(scala, scalaJS, cached)) + testAllMatrix((scala, scalaJS, _) => checkUtest(scala, scalaJS, cached), skipScala = _.startsWith("2.11.")) + testAllMatrix((scala, scalaJS, _) => checkScalaTest(scala, scalaJS, cached)) } 'testCached - { val cached = false - testAllMatrix((scala, scalaJS) => checkUtest(scala, scalaJS, cached), skipScala = _.startsWith("2.11.")) - testAllMatrix((scala, scalaJS) => checkScalaTest(scala, scalaJS, cached)) + testAllMatrix((scala, scalaJS, _) => checkUtest(scala, scalaJS, cached), skipScala = _.startsWith("2.11.")) + testAllMatrix((scala, scalaJS, _) => checkScalaTest(scala, scalaJS, cached)) } - def checkRun(scalaVersion: String, scalaJSVersion: String): Unit = { - val task = HelloJSWorld.helloJsWorld(scalaVersion, scalaJSVersion).run() + def checkRun(scalaVersion: String, scalaJSVersion: String, useECMAScript2015: Boolean): Unit = { + val task = HelloJSWorld.helloJsWorld(scalaVersion, scalaJSVersion, useECMAScript2015).run() val Right((_, evalCount)) = helloWorldEvaluator(task) @@ -228,7 +229,7 @@ object HelloJSWorldTests extends TestSuite { } 'run - { - testAllMatrix((scala, scalaJS) => checkRun(scala, scalaJS)) + testAllMatrix((scala, scalaJS, useECMAScript2015) => checkRun(scala, scalaJS, useECMAScript2015), skipECMAScript2015 = false) } } @@ -260,18 +261,20 @@ object HelloJSWorldTests extends TestSuite { os.copy(millSourcePath, workspacePath) } - def testAllMatrix(f: (String, String) => Unit, + def testAllMatrix(f: (String, String, Boolean) => Unit, skipScala: String => Boolean = _ => false, - skipScalaJS: String => Boolean = _ => false): Unit = { + skipScalaJS: String => Boolean = _ => false, + skipECMAScript2015: Boolean = true): Unit = { for { - (scala, scalaJS) <- HelloJSWorld.matrix + (scala, scalaJS, useECMAScript2015) <- HelloJSWorld.matrix if !skipScala(scala) if !skipScalaJS(scalaJS) + if !skipECMAScript2015 && useECMAScript2015 } { if(scala.startsWith("2.11.")) { - TestUtil.disableInJava9OrAbove(f(scala,scalaJS)) + TestUtil.disableInJava9OrAbove(f(scala,scalaJS, useECMAScript2015)) } else { - f(scala,scalaJS) + f(scala,scalaJS, useECMAScript2015) } } } diff --git a/scalajslib/test/src/MultiModuleTests.scala b/scalajslib/test/src/MultiModuleTests.scala index 05670bfac77..1177968032c 100644 --- a/scalajslib/test/src/MultiModuleTests.scala +++ b/scalajslib/test/src/MultiModuleTests.scala @@ -13,8 +13,8 @@ object MultiModuleTests extends TestSuite { object MultiModule extends TestUtil.BaseModule { trait BaseModule extends ScalaJSModule { - def scalaVersion = "2.12.4" - def scalaJSVersion = "0.6.32" + def scalaVersion = "2.13.3" + def scalaJSVersion = "0.6.33" } object client extends BaseModule { @@ -23,7 +23,7 @@ object MultiModuleTests extends TestSuite { override def mainClass = Some("Main") object test extends Tests { def testFrameworks = Seq("utest.runner.Framework") - override def ivyDeps = Agg(ivy"com.lihaoyi::utest::0.6.3") + override def ivyDeps = Agg(ivy"com.lihaoyi::utest::0.7.5") } } @@ -49,7 +49,7 @@ object MultiModuleTests extends TestSuite { val runOutput = ScalaJsUtils.runJS(linked.path) assert( evalCount > 0, - runOutput == "Hello from Scala.js, result is: 3" + runOutput == "Hello from Scala.js, result is: 3\n" ) } diff --git a/scalajslib/test/src/ScalaJsUtils.scala b/scalajslib/test/src/ScalaJsUtils.scala index 1e6240d2a24..ecfbd3bdf60 100644 --- a/scalajslib/test/src/ScalaJsUtils.scala +++ b/scalajslib/test/src/ScalaJsUtils.scala @@ -1,25 +1,7 @@ package mill.scalajslib -import java.io.{FileReader, StringWriter} -import javax.script.{ScriptContext, ScriptEngineManager} - object ScalaJsUtils { - /* TODO Using Nashorn means that we do not support ECMAScript 2015, which - * forces ScalaJSWorkerImpl to always use ES 5.1. We should a different - * engine, perhaps Scala.js' own JSEnv, to perform these tests. - */ def runJS(path: os.Path): String = { - val engineManager = new ScriptEngineManager(null) - val engine = engineManager.getEngineByName("nashorn") - val console = new Console - val bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE) - bindings.put("console", console) - engine.eval(new FileReader(path.toIO)) - console.out.toString + os.proc("node", path).call().out.text } } - -class Console { - val out = new StringWriter() - def log(s: String): Unit = out.append(s) -} diff --git a/scalajslib/worker/0.6/src/ScalaJSWorkerImpl.scala b/scalajslib/worker/0.6/src/ScalaJSWorkerImpl.scala index 38ec118c67b..74073023ba1 100644 --- a/scalajslib/worker/0.6/src/ScalaJSWorkerImpl.scala +++ b/scalajslib/worker/0.6/src/ScalaJSWorkerImpl.scala @@ -15,14 +15,15 @@ import org.scalajs.jsenv._ import org.scalajs.testadapter.TestAdapter class ScalaJSWorkerImpl extends mill.scalajslib.api.ScalaJSWorkerApi { - + def link(sources: Array[File], libraries: Array[File], dest: File, main: String, testBridgeInit: Boolean, // ignored in 0.6 fullOpt: Boolean, - moduleKind: ModuleKind) = { + moduleKind: ModuleKind, + useECMAScript2015: Boolean) = { val semantics = fullOpt match { case true => Semantics.Defaults.optimized @@ -31,12 +32,14 @@ class ScalaJSWorkerImpl extends mill.scalajslib.api.ScalaJSWorkerApi { val scalaJSModuleKind = moduleKind match { case ModuleKind.NoModule => ScalaJSModuleKind.NoModule case ModuleKind.CommonJSModule => ScalaJSModuleKind.CommonJSModule + case ModuleKind.ESModule => ScalaJSModuleKind.ESModule } val config = StandardLinker.Config() .withOptimizer(fullOpt) .withClosureCompilerIfAvailable(fullOpt) .withSemantics(semantics) .withModuleKind(scalaJSModuleKind) + .withESFeatures(_.withUseECMAScript2015(useECMAScript2015)) val linker = StandardLinker(config) val sourceSJSIRs = sources.map(new FileVirtualScalaJSIRFile(_)) val jars = libraries.map(jar => IRContainer.Jar(new FileVirtualBinaryFile(jar) with VirtualJarFile)) @@ -71,6 +74,7 @@ class ScalaJSWorkerImpl extends mill.scalajslib.api.ScalaJSWorkerApi { val tconfig = moduleKind match { case ModuleKind.NoModule => TestAdapter.Config().withLogger(new ScalaConsoleLogger) case ModuleKind.CommonJSModule => TestAdapter.Config().withLogger(new ScalaConsoleLogger).withModuleSettings(ScalaJSModuleKind.CommonJSModule, moduleIdentifier) + case ModuleKind.ESModule => TestAdapter.Config().withLogger(new ScalaConsoleLogger).withModuleSettings(ScalaJSModuleKind.ESModule, moduleIdentifier) } val adapter = diff --git a/scalajslib/worker/1/src/ScalaJSWorkerImpl.scala b/scalajslib/worker/1/src/ScalaJSWorkerImpl.scala index 955f9ce7089..749308bc6f3 100644 --- a/scalajslib/worker/1/src/ScalaJSWorkerImpl.scala +++ b/scalajslib/worker/1/src/ScalaJSWorkerImpl.scala @@ -23,7 +23,8 @@ class ScalaJSWorkerImpl extends mill.scalajslib.api.ScalaJSWorkerApi { main: String, testBridgeInit: Boolean, fullOpt: Boolean, - moduleKind: ModuleKind) = { + moduleKind: ModuleKind, + useECMAScript2015: Boolean) = { import scala.concurrent.ExecutionContext.Implicits.global val semantics = fullOpt match { case true => Semantics.Defaults.optimized @@ -32,19 +33,14 @@ class ScalaJSWorkerImpl extends mill.scalajslib.api.ScalaJSWorkerApi { val scalaJSModuleKind = moduleKind match { case ModuleKind.NoModule => ScalaJSModuleKind.NoModule case ModuleKind.CommonJSModule => ScalaJSModuleKind.CommonJSModule + case ModuleKind.ESModule => ScalaJSModuleKind.ESModule } - /* TODO We currently force ECMAScript 5.1, because the *tests* of - * scalajslib use Nashorn (see ScalaJsUtils.scala) which does not support - * ES 2015. This should at least be turned into a configuration option, but - * also we should change ScalaJsUtils to support ES 2015, for example by - * using Scala.js' own NodeJSEnv to perform the tests. - */ val config = StandardConfig() .withOptimizer(fullOpt) .withClosureCompilerIfAvailable(fullOpt) .withSemantics(semantics) .withModuleKind(scalaJSModuleKind) - .withESFeatures(_.withUseECMAScript2015(false)) + .withESFeatures(_.withUseECMAScript2015(useECMAScript2015)) val linker = StandardImpl.linker(config) val cache = StandardImpl.irFileCache().newCache val sourceIRsFuture = Future.sequence(sources.toSeq.map(f => PathIRFile(f.toPath())))