Skip to content

Commit

Permalink
Support useECMAScript215 option in ScalaJSModule
Browse files Browse the repository at this point in the history
- Support ESModule ModuleKind
- Update Scala.js 0.6 to 0.6.33
- Update Scala.js 1 to 1.3.1
- Add useECMAScript215 to test matrix just for last version
- Update Scala versions it tests
- Update ScalaJsUtils to use node.js instead of nashorn
  The initial idea was to use the NodeJSEnv from Scala.js to run the
  tests. But this created a problem since adding a particular NodeJSEnv
  to the classpath broke the other version of Scala.js linking. For example
  using NodeJSEnv from Scala.js 1.3.1 made fastOpt in Scala.js 0.6 break.
  So at the end the function is just calling "node" using `os.proc`
  • Loading branch information
lolgab committed Nov 17, 2020
1 parent f7150b6 commit 51999ea
Show file tree
Hide file tree
Showing 9 changed files with 75 additions and 79 deletions.
10 changes: 5 additions & 5 deletions build.sc
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
4 changes: 3 additions & 1 deletion scalajslib/api/src/ScalaJSWorkerApi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -29,6 +30,7 @@ sealed trait ModuleKind
object ModuleKind{
object NoModule extends ModuleKind
object CommonJSModule extends ModuleKind
object ESModule extends ModuleKind
}


Expand Down
17 changes: 12 additions & 5 deletions scalajslib/src/ScalaJSModule.scala
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ trait ScalaJSModule extends scalalib.ScalaModule { outer =>
finalMainClassOpt().toOption,
testBridgeInit = false,
FastOpt,
moduleKind()
moduleKind(),
useECMAScript2015()
)
}

Expand All @@ -87,7 +88,8 @@ trait ScalaJSModule extends scalalib.ScalaModule { outer =>
finalMainClassOpt().toOption,
testBridgeInit = false,
FullOpt,
moduleKind()
moduleKind(),
useECMAScript2015()
)
}

Expand Down Expand Up @@ -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)
Expand All @@ -141,7 +144,8 @@ trait ScalaJSModule extends scalalib.ScalaModule { outer =>
mainClass,
testBridgeInit,
mode == FullOpt,
moduleKind
moduleKind,
useECMAScript2015
).map(PathRef(_))
}

Expand All @@ -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 {
Expand All @@ -190,7 +196,8 @@ trait TestScalaJSModule extends ScalaJSModule with TestModule {
None,
testBridgeInit = true,
FastOpt,
moduleKind()
moduleKind(),
useECMAScript2015()
)
}

Expand Down
6 changes: 4 additions & 2 deletions scalajslib/src/ScalaJSWorkerApi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -46,7 +47,8 @@ class ScalaJSWorker {
main.orNull,
testBridgeInit,
fullOpt,
moduleKind
moduleKind,
useECMAScript2015
).map(os.Path(_))
}

Expand Down
69 changes: 36 additions & 33 deletions scalajslib/test/src/HelloJSWorldTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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")
Expand All @@ -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")
Expand All @@ -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)
Expand All @@ -96,40 +96,41 @@ 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
assert(ujson.read(sourceMap.toIO).obj.get("file").exists(_.str == jsFile.toNIO.getFileName.toString)) // sourceMap references jsFile
}

'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"))
Expand All @@ -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]] = {
Expand Down Expand Up @@ -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)

Expand All @@ -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)
}
}

Expand Down Expand Up @@ -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)
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions scalajslib/test/src/MultiModuleTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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")
}
}

Expand All @@ -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"
)
}

Expand Down
20 changes: 1 addition & 19 deletions scalajslib/test/src/ScalaJsUtils.scala
Original file line number Diff line number Diff line change
@@ -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)
}
8 changes: 6 additions & 2 deletions scalajslib/worker/0.6/src/ScalaJSWorkerImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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 /* ignored in 0.6 */) = {

val semantics = fullOpt match {
case true => Semantics.Defaults.optimized
Expand All @@ -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))
Expand Down Expand Up @@ -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 =
Expand Down
Loading

0 comments on commit 51999ea

Please sign in to comment.