summaryrefslogtreecommitdiff
path: root/project
diff options
context:
space:
mode:
Diffstat (limited to 'project')
-rw-r--r--project/ExternalCompile.scala116
-rw-r--r--project/JavaLangObject.scala243
-rw-r--r--project/JavaLangString.scala215
-rw-r--r--project/ScalaJSBuild.scala891
-rw-r--r--project/build.properties1
-rw-r--r--project/build.sbt48
-rw-r--r--project/project/ScalaJSEnvGenerator.scala31
7 files changed, 1545 insertions, 0 deletions
diff --git a/project/ExternalCompile.scala b/project/ExternalCompile.scala
new file mode 100644
index 0000000..7d37c81
--- /dev/null
+++ b/project/ExternalCompile.scala
@@ -0,0 +1,116 @@
+import sbt._
+import Keys._
+
+import scala.scalajs.sbtplugin.ScalaJSPlugin
+import ScalaJSPlugin.autoImport.jsDependencyManifest
+
+object ExternalCompile {
+
+ private val isWindows =
+ System.getProperty("os.name").toLowerCase().indexOf("win") >= 0
+
+ val scalaJSExternalCompileConfigSettings: Seq[Setting[_]] = inTask(compile)(
+ Defaults.runnerTask
+ ) ++ Seq(
+ fork in compile := true,
+ trapExit in compile := true,
+ javaOptions in compile += "-Xmx512M",
+
+ compile := {
+ val inputs = (compileInputs in compile).value
+ import inputs.config._
+
+ val s = streams.value
+ val logger = s.log
+ val cacheDir = s.cacheDirectory
+
+ // Discover classpaths
+
+ def cpToString(cp: Seq[File]) =
+ cp.map(_.getAbsolutePath).mkString(java.io.File.pathSeparator)
+
+ val compilerCp = inputs.compilers.scalac.scalaInstance.allJars
+ val cpStr = cpToString(classpath)
+
+ // List all my dependencies (recompile if any of these changes)
+
+ val allMyDependencies = classpath filterNot (_ == classesDirectory) flatMap { cpFile =>
+ if (cpFile.isDirectory) (cpFile ** "*.class").get
+ else Seq(cpFile)
+ }
+
+ // Compile
+
+ val cachedCompile = FileFunction.cached(cacheDir / "compile",
+ FilesInfo.lastModified, FilesInfo.exists) { dependencies =>
+
+ logger.info(
+ "Compiling %d Scala sources to %s..." format (
+ sources.size, classesDirectory))
+
+ if (classesDirectory.exists)
+ IO.delete(classesDirectory)
+ IO.createDirectory(classesDirectory)
+
+ val sourcesArgs = sources.map(_.getAbsolutePath()).toList
+
+ /* run.run() below in doCompileJS() will emit a call to its
+ * logger.info("Running scala.tools.nsc.scalajs.Main [...]")
+ * which we do not want to see. We use this patched logger to
+ * filter out that particular message.
+ */
+ val patchedLogger = new Logger {
+ def log(level: Level.Value, message: => String) = {
+ val msg = message
+ if (level != Level.Info ||
+ !msg.startsWith("Running scala.tools.nsc.Main"))
+ logger.log(level, msg)
+ }
+ def success(message: => String) = logger.success(message)
+ def trace(t: => Throwable) = logger.trace(t)
+ }
+
+ def doCompile(sourcesArgs: List[String]): Unit = {
+ val run = (runner in compile).value
+ run.run("scala.tools.nsc.Main", compilerCp,
+ "-cp" :: cpStr ::
+ "-d" :: classesDirectory.getAbsolutePath() ::
+ options ++:
+ sourcesArgs,
+ patchedLogger) foreach sys.error
+ }
+
+ /* Crude way of overcoming the Windows limitation on command line
+ * length.
+ */
+ if ((fork in compile).value && isWindows &&
+ (sourcesArgs.map(_.length).sum > 1536)) {
+ IO.withTemporaryFile("sourcesargs", ".txt") { sourceListFile =>
+ IO.writeLines(sourceListFile, sourcesArgs)
+ doCompile(List("@"+sourceListFile.getAbsolutePath()))
+ }
+ } else {
+ doCompile(sourcesArgs)
+ }
+
+ // Output is all files in classesDirectory
+ (classesDirectory ** AllPassFilter).get.toSet
+ }
+
+ cachedCompile((sources ++ allMyDependencies).toSet)
+
+ // We do not have dependency analysis when compiling externally
+ sbt.inc.Analysis.Empty
+ },
+
+ // Make sure jsDependencyManifest runs after compile, otherwise compile
+ // might remove the entire directory afterwards.
+ jsDependencyManifest <<= jsDependencyManifest.dependsOn(compile)
+ )
+
+ val scalaJSExternalCompileSettings = (
+ inConfig(Compile)(scalaJSExternalCompileConfigSettings) ++
+ inConfig(Test)(scalaJSExternalCompileConfigSettings)
+ )
+
+}
diff --git a/project/JavaLangObject.scala b/project/JavaLangObject.scala
new file mode 100644
index 0000000..ff82b94
--- /dev/null
+++ b/project/JavaLangObject.scala
@@ -0,0 +1,243 @@
+/*
+ * Hard-coded IR for java.lang.Object.
+ */
+
+import scala.scalajs.ir
+import ir._
+import ir.Definitions._
+import ir.Infos._
+import ir.Trees._
+import ir.Types._
+import ir.Position.NoPosition
+
+/** Hard-coded IR for java.lang.Object.
+ * We cannot so much as begin to fake a compilation of java.lang.Object,
+ * because Object is hijacked so much by scalac itself that it does not like
+ * at all to try to compile that class. So we have to bypass entirely the
+ * compiler to define java.lang.Object.
+ */
+object JavaLangObject {
+
+ /** Optimizer hints with `@inline`
+ * Unfortunately we do not have access to private details of
+ * [[OptimizerHints]], so we cannot do this cleanly. But it is fine
+ * somehow because we're part of the same project implementation.
+ */
+ private def inlineOptimizerHints = new OptimizerHints(2)
+
+ val InfoAndTree = (Info, Definition)
+
+ private def Info = ClassInfo(
+ name = "java.lang.Object",
+ encodedName = "O",
+ ancestorCount = 0,
+ kind = ClassKind.Class,
+ superClass = "",
+ ancestors = List("O"),
+ methods = List(
+ MethodInfo("__init__"),
+ MethodInfo("init___"),
+ MethodInfo("hashCode__I",
+ calledMethods = Map(
+ "jl_System$" -> List("identityHashCode__O__I")
+ ),
+ accessedModules = List("jl_System")
+ ),
+ MethodInfo("equals__O__Z",
+ optimizerHints = inlineOptimizerHints
+ ),
+ MethodInfo("clone__O",
+ calledMethods = Map(
+ "sjsr_package$" -> List("cloneObject__sjs_js_Object__sjs_js_Object"),
+ "jl_CloneNotSupportedException" -> List("init___")
+ ),
+ instantiatedClasses = List("jl_CloneNotSupportedException"),
+ accessedModules = List("sjsr_package"),
+ accessedClassData = List("jl_Cloneable"),
+ optimizerHints = inlineOptimizerHints
+ ),
+ MethodInfo("notify__V"),
+ MethodInfo("notifyAll__V"),
+ MethodInfo("toString__T",
+ calledMethods = Map(
+ "O" -> List("hashCode__I"),
+ "jl_Class" -> List("getName__T"),
+ "jl_Integer$" -> List("toHexString__I__T")
+ ),
+ accessedModules = List("jl_Integer")
+ ),
+ MethodInfo("finalize__V"),
+ MethodInfo("clone__",
+ calledMethods = Map(
+ "O" -> List("clone__O")
+ )
+ ),
+ MethodInfo("notify__",
+ calledMethods = Map(
+ "O" -> List("notify__V")
+ )
+ ),
+ MethodInfo("notifyAll__",
+ calledMethods = Map(
+ "O" -> List("notifyAll__V")
+ )
+ ),
+ MethodInfo("finalize__",
+ calledMethods = Map(
+ "O" -> List("finalize__V")
+ )
+ )
+ )
+ )
+
+ private def Definition = {
+ implicit val DummyPos = NoPosition
+
+ // ClassType(Object) is normally invalid, but not in this class def
+ val ThisType = ClassType(ObjectClass)
+
+ val classDef = ClassDef(
+ Ident("O", Some("java.lang.Object")),
+ ClassKind.Class,
+ None,
+ Nil,
+ List(
+ /* def this() = () */
+ MethodDef(
+ Ident("init___", Some("<init>")),
+ Nil,
+ AnyType,
+ This()(ThisType))(None),
+
+ /* def hashCode(): Int = System.identityHashCode(this) */
+ MethodDef(
+ Ident("hashCode__I", Some("hashCode__I")),
+ Nil,
+ IntType,
+ {
+ Apply(
+ LoadModule(ClassType("jl_System$")),
+ Ident("identityHashCode__O__I", Some("identityHashCode")),
+ List(This()(ThisType)))(IntType)
+ })(None),
+
+ /* def equals(that: Object): Boolean = this eq that */
+ MethodDef(
+ Ident("equals__O__Z", Some("equals__O__Z")),
+ List(ParamDef(Ident("that", Some("that")), AnyType, mutable = false)),
+ BooleanType,
+ {
+ BinaryOp(BinaryOp.===,
+ This()(ThisType),
+ VarRef(Ident("that", Some("that")), mutable = false)(AnyType))
+ })(None),
+
+ /* protected def clone(): Object =
+ * if (this.isInstanceOf[Cloneable]) <clone>(this)
+ * else throw new CloneNotSupportedException()
+ */
+ MethodDef(
+ Ident("clone__O", Some("clone__O")),
+ Nil,
+ AnyType,
+ {
+ If(IsInstanceOf(This()(ThisType), ClassType("jl_Cloneable")), {
+ Apply(LoadModule(ClassType("sjsr_package$")),
+ Ident("cloneObject__sjs_js_Object__sjs_js_Object", Some("cloneObject")),
+ List(This()(ThisType)))(AnyType)
+ }, {
+ Throw(New(ClassType("jl_CloneNotSupportedException"),
+ Ident("init___", Some("<init>")), Nil))
+ })(AnyType)
+ })(None),
+
+ /* def toString(): String =
+ * getClass().getName() + "@" + Integer.toHexString(hashCode())
+ */
+ MethodDef(
+ Ident("toString__T", Some("toString__T")),
+ Nil,
+ ClassType(StringClass),
+ {
+ BinaryOp(BinaryOp.String_+, BinaryOp(BinaryOp.String_+,
+ Apply(
+ GetClass(This()(ThisType)),
+ Ident("getName__T"), Nil)(ClassType(StringClass)),
+ // +
+ StringLiteral("@")),
+ // +
+ Apply(
+ LoadModule(ClassType("jl_Integer$")),
+ Ident("toHexString__I__T"),
+ List(Apply(This()(ThisType), Ident("hashCode__I"), Nil)(IntType)))(
+ ClassType(StringClass)))
+ })(None),
+
+ /* Since wait() is not supported in any way, a correct implementation
+ * of notify() and notifyAll() is to do nothing.
+ */
+
+ /* def notify(): Unit = () */
+ MethodDef(
+ Ident("notify__V", Some("notify__V")),
+ Nil,
+ NoType,
+ Skip())(None),
+
+ /* def notifyAll(): Unit = () */
+ MethodDef(
+ Ident("notifyAll__V", Some("notifyAll__V")),
+ Nil,
+ NoType,
+ Skip())(None),
+
+ /* def finalize(): Unit = () */
+ MethodDef(
+ Ident("finalize__V", Some("finalize__V")),
+ Nil,
+ NoType,
+ Skip())(None),
+
+ /* Reflective proxies
+ * Note that we do not need to proxy the following methods, since
+ * they are defined on Any in the Scala hierarchy and therefore a
+ * reflective call is never emitted:
+ * - equals
+ * - getClass
+ * - hashCode
+ * - toString
+ */
+
+ MethodDef(Ident("clone__"), Nil, AnyType,
+ Apply(This()(ThisType), Ident("clone__O"), Nil)(AnyType))(None),
+
+ MethodDef(Ident("notify__"), Nil, AnyType, Block(
+ Apply(This()(ThisType), Ident("notify__V"), Nil)(NoType),
+ Undefined()))(None),
+
+ MethodDef(Ident("notifyAll__"), Nil, AnyType, Block(
+ Apply(This()(ThisType), Ident("notifyAll__V"), Nil)(NoType),
+ Undefined()))(None),
+
+ MethodDef(Ident("finalize__"), Nil, AnyType, Block(
+ Apply(This()(ThisType), Ident("finalize__V"), Nil)(NoType),
+ Undefined()))(None),
+
+ // Exports
+
+ /* JSExport for toString(). */
+ MethodDef(
+ StringLiteral("toString"),
+ Nil,
+ AnyType,
+ {
+ Apply(This()(ThisType),
+ Ident("toString__T", Some("toString__T")),
+ Nil)(ClassType(StringClass))
+ })(None)
+ ))
+
+ Hashers.hashClassDef(classDef)
+ }
+
+}
diff --git a/project/JavaLangString.scala b/project/JavaLangString.scala
new file mode 100644
index 0000000..fc68b29
--- /dev/null
+++ b/project/JavaLangString.scala
@@ -0,0 +1,215 @@
+/*
+ * Hard-coded IR for java.lang.String.
+ */
+
+import scala.scalajs.ir
+import ir._
+import ir.Definitions._
+import ir.Infos._
+import ir.Trees._
+import ir.Types._
+import ir.Position.NoPosition
+
+/** Hard-coded IR for java.lang.String.
+ * Unlike for the other hijacked classes, scalac does not like at all to
+ * compile even a mocked version of java.lang.String. So we have to bypass
+ * entirely the compiler to define java.lang.String.
+ */
+object JavaLangString {
+
+ /** Optimizer hints with `@inline`
+ * Unfortunately we do not have access to private details of
+ * [[OptimizerHints]], so we cannot do this cleanly. But it is fine
+ * somehow because we're part of the same project implementation.
+ */
+ private def inlineOptimizerHints = new OptimizerHints(2)
+
+ val InfoAndTree = (Info, Definition)
+
+ private def Info = ClassInfo(
+ name = "java.lang.String",
+ encodedName = "T",
+ ancestorCount = 1,
+ kind = ClassKind.HijackedClass,
+ superClass = "O",
+ ancestors = List(
+ "T", "Ljava_io_Serializable", "jl_CharSequence", "jl_Comparable", "O"),
+ methods = List(
+ MethodInfo("equals__O__Z",
+ optimizerHints = inlineOptimizerHints
+ ),
+ MethodInfo("hashCode__I",
+ calledMethods = Map(
+ "sjsr_RuntimeString$" -> List("hashCode__T__I")
+ ),
+ accessedModules = List("sjsr_RuntimeString"),
+ optimizerHints = inlineOptimizerHints
+ ),
+ MethodInfo("compareTo__T__I",
+ calledMethods = Map(
+ "sjsr_RuntimeString$" -> List("compareTo__T__T__I")
+ ),
+ accessedModules = List("sjsr_RuntimeString"),
+ optimizerHints = inlineOptimizerHints
+ ),
+ MethodInfo("compareTo__O__I",
+ calledMethods = Map(
+ "T" -> List("compareTo__T__I")
+ ),
+ optimizerHints = inlineOptimizerHints
+ ),
+ MethodInfo("toString__T",
+ optimizerHints = inlineOptimizerHints
+ ),
+ MethodInfo("charAt__I__C",
+ calledMethods = Map(
+ "sjsr_RuntimeString$" -> List("charAt__T__I__C")
+ ),
+ accessedModules = List("sjsr_RuntimeString"),
+ optimizerHints = inlineOptimizerHints
+ ),
+ MethodInfo("length__I",
+ calledMethods = Map(
+ "sjsr_RuntimeString$" -> List("length__T__I")
+ ),
+ accessedModules = List("sjsr_RuntimeString"),
+ optimizerHints = inlineOptimizerHints
+ ),
+ MethodInfo("subSequence__I__I__jl_CharSequence",
+ calledMethods = Map(
+ "sjsr_RuntimeString$" -> List("subSequence__T__I__I__jl_CharSequence")
+ ),
+ accessedModules = List("sjsr_RuntimeString"),
+ optimizerHints = inlineOptimizerHints
+ )
+ )
+ )
+
+ private def Definition = {
+ implicit val DummyPos = NoPosition
+
+ val ThisType = ClassType(StringClass)
+
+ ClassDef(
+ Ident("T", Some("java.lang.String")),
+ ClassKind.HijackedClass,
+ Some(Ident("O", Some("java.lang.Object"))),
+ List(
+ Ident("Ljava_io_Serializable", Some("java.io.Serializable")),
+ Ident("jl_CharSequence", Some("java.lang.CharSequence")),
+ Ident("jl_Comparable", Some("java.lang.Comparable")),
+ Ident("O", Some("java.lang.Object"))
+ ),
+ List(
+ /* def equals(that: Object): Boolean = this eq that */
+ MethodDef(
+ Ident("equals__O__Z", Some("equals__O__Z")),
+ List(ParamDef(Ident("that", Some("that")), AnyType, mutable = false)),
+ BooleanType,
+ {
+ BinaryOp(BinaryOp.===,
+ This()(ThisType),
+ VarRef(Ident("that", Some("that")), mutable = false)(AnyType))
+ })(None),
+
+ /* def hashCode(): Int = RuntimeString.hashCode(this) */
+ MethodDef(
+ Ident("hashCode__I", Some("hashCode__I")),
+ Nil,
+ IntType,
+ {
+ Apply(
+ LoadModule(ClassType("sjsr_RuntimeString$")),
+ Ident("hashCode__T__I", Some("hashCode__T__I")),
+ List(This()(ThisType)))(IntType)
+ })(None),
+
+ /* def compareTo(that: String): Int = RuntimeString.compareTo(this, that) */
+ MethodDef(
+ Ident("compareTo__T__I", Some("compareTo__T__I")),
+ List(ParamDef(Ident("that", Some("that")), ThisType, mutable = false)),
+ IntType,
+ {
+ Apply(
+ LoadModule(ClassType("sjsr_RuntimeString$")),
+ Ident("compareTo__T__T__I", Some("compareTo__T__T__I")),
+ List(
+ This()(ThisType),
+ VarRef(Ident("that", Some("that")), mutable = false)(ThisType)))(IntType)
+ })(None),
+
+ /* def compareTo(that: Object): Int = compareTo(that.asInstanceOf[String]) */
+ MethodDef(
+ Ident("compareTo__O__I", Some("compareTo__O__I")),
+ List(ParamDef(Ident("that", Some("that")), AnyType, mutable = false)),
+ IntType,
+ {
+ Apply(
+ This()(ThisType),
+ Ident("compareTo__T__I", Some("compareTo__T__I")),
+ List(AsInstanceOf(
+ VarRef(Ident("that", Some("that")), mutable = false)(AnyType),
+ ThisType)))(IntType)
+ })(None),
+
+ /* def toString(): String = this */
+ MethodDef(
+ Ident("toString__T", Some("toString__T")),
+ Nil,
+ ClassType(StringClass),
+ {
+ This()(ThisType)
+ })(None),
+
+ /* def charAt(i: Int): Char = RuntimeString.charAt(this, i) */
+ MethodDef(
+ Ident("charAt__I__C", Some("charAt__I__C")),
+ List(ParamDef(Ident("i", Some("i")), IntType, mutable = false)),
+ IntType,
+ {
+ Apply(
+ LoadModule(ClassType("sjsr_RuntimeString$")),
+ Ident("charAt__T__I__C", Some("charAt__T__I__C")),
+ List(
+ This()(ThisType),
+ VarRef(Ident("i", Some("i")), mutable = false)(IntType)))(IntType)
+ })(None),
+
+ /* def length(): Int = RuntimeString.length(this) */
+ MethodDef(
+ Ident("length__I", Some("length__I")),
+ Nil,
+ IntType,
+ {
+ Apply(
+ LoadModule(ClassType("sjsr_RuntimeString$")),
+ Ident("length__T__I", Some("length__T__I")),
+ List(This()(ThisType)))(IntType)
+ })(None),
+
+ /* def subSequence(begin: Int, end: Int): CharSequence =
+ * RuntimeString.subSequence(this, begin, end)
+ */
+ MethodDef(
+ Ident("subSequence__I__I__jl_CharSequence",
+ Some("subSequence__I__I__jl_CharSequence")),
+ List(
+ ParamDef(Ident("begin", Some("begin")), IntType, mutable = false),
+ ParamDef(Ident("end", Some("end")), IntType, mutable = false)
+ ),
+ ClassType("jl_CharSequence"),
+ {
+ Apply(
+ LoadModule(ClassType("sjsr_RuntimeString$")),
+ Ident("subSequence__T__I__I__jl_CharSequence",
+ Some("subSequence__T__I__I__jl_CharSequence")),
+ List(
+ This()(ThisType),
+ VarRef(Ident("begin", Some("begin")), mutable = false)(IntType),
+ VarRef(Ident("end", Some("end")), mutable = false)(IntType)))(
+ ClassType("jl_CharSequence"))
+ })(None)
+ ))
+ }
+
+}
diff --git a/project/ScalaJSBuild.scala b/project/ScalaJSBuild.scala
new file mode 100644
index 0000000..5cbc405
--- /dev/null
+++ b/project/ScalaJSBuild.scala
@@ -0,0 +1,891 @@
+import sbt._
+import Keys._
+
+import bintray.Plugin.bintrayPublishSettings
+import bintray.Keys.{repository, bintrayOrganization, bintray}
+
+import java.io.{
+ BufferedOutputStream,
+ FileOutputStream,
+ BufferedWriter,
+ FileWriter
+}
+
+import scala.collection.mutable
+import scala.util.Properties
+
+import scala.scalajs.ir
+import scala.scalajs.sbtplugin._
+import scala.scalajs.sbtplugin.env.rhino.RhinoJSEnv
+import ScalaJSPlugin.autoImport._
+import ExternalCompile.scalaJSExternalCompileSettings
+import Implicits._
+
+import scala.scalajs.tools.sourcemap._
+import scala.scalajs.tools.io.MemVirtualJSFile
+
+import sbtassembly.Plugin.{AssemblyKeys, assemblySettings}
+import AssemblyKeys.{assembly, assemblyOption}
+
+object ScalaJSBuild extends Build {
+
+ val fetchedScalaSourceDir = settingKey[File](
+ "Directory the scala source is fetched to")
+ val fetchScalaSource = taskKey[File](
+ "Fetches the scala source for the current scala version")
+ val shouldPartest = settingKey[Boolean](
+ "Whether we should partest the current scala version (and fail if we can't)")
+
+ val commonSettings = Seq(
+ organization := "org.scala-lang.modules.scalajs",
+ version := scalaJSVersion,
+
+ normalizedName ~= {
+ _.replace("scala.js", "scalajs").replace("scala-js", "scalajs")
+ },
+
+ homepage := Some(url("http://scala-js.org/")),
+ licenses += ("BSD New",
+ url("https://github.com/scala-js/scala-js/blob/master/LICENSE")),
+
+ shouldPartest := {
+ val testListDir = (
+ (resourceDirectory in (partestSuite, Test)).value / "scala"
+ / "tools" / "partest" / "scalajs" / scalaVersion.value
+ )
+ testListDir.exists
+ },
+
+ scalacOptions ++= Seq(
+ "-deprecation",
+ "-unchecked",
+ "-feature",
+ "-encoding", "utf8"
+ )
+ )
+
+ private val snapshotsOrReleases =
+ if (scalaJSIsSnapshotVersion) "snapshots" else "releases"
+
+ private def publishToScalaJSRepoSettings = Seq(
+ publishTo := {
+ Seq("PUBLISH_USER", "PUBLISH_PASS").map(Properties.envOrNone) match {
+ case Seq(Some(user), Some(pass)) =>
+ Some(Resolver.sftp(
+ s"scala-js-$snapshotsOrReleases",
+ "repo.scala-js.org",
+ s"/home/scalajsrepo/www/repo/$snapshotsOrReleases")(
+ Resolver.ivyStylePatterns) as (user, pass))
+ case _ =>
+ None
+ }
+ }
+ )
+
+ private def publishToBintraySettings = (
+ bintrayPublishSettings
+ ) ++ Seq(
+ repository in bintray := "scala-js-releases",
+ bintrayOrganization in bintray := Some("scala-js")
+ )
+
+ val publishSettings = (
+ if (Properties.envOrNone("PUBLISH_TO_BINTRAY") == Some("true"))
+ publishToBintraySettings
+ else
+ publishToScalaJSRepoSettings
+ ) ++ Seq(
+ publishMavenStyle := false
+ )
+
+ val defaultSettings = commonSettings ++ Seq(
+ scalaVersion := "2.11.2"
+ )
+
+ val myScalaJSSettings = ScalaJSPluginInternal.scalaJSAbstractSettings ++ Seq(
+ autoCompilerPlugins := true,
+ scalaJSOptimizerOptions ~= (_.withCheckScalaJSIR(true))
+ )
+
+ val scalaJSSourceMapSettings = scalacOptions ++= {
+ if (scalaJSIsSnapshotVersion) Seq()
+ else Seq(
+ // Link source maps to github sources
+ "-P:scalajs:mapSourceURI:" + root.base.toURI +
+ "->https://raw.githubusercontent.com/scala-js/scala-js/v" +
+ scalaJSVersion + "/"
+ )
+ }
+
+ /** Depend library as if (exportJars in library) was set to false */
+ val compileWithLibrarySetting = {
+ internalDependencyClasspath in Compile ++= {
+ val prods = (products in (library, Compile)).value
+ val analysis = (compile in (library, Compile)).value
+
+ prods.map(p => Classpaths.analyzed(p, analysis))
+ }
+ }
+
+ // Used when compiling the compiler, adding it to scalacOptions does not help
+ scala.util.Properties.setProp("scalac.patmat.analysisBudget", "1024")
+
+ override lazy val settings = super.settings ++ Seq(
+ // Most of the projects cross-compile
+ crossScalaVersions := Seq(
+ "2.10.2",
+ "2.10.3",
+ "2.10.4",
+ "2.11.0",
+ "2.11.1",
+ "2.11.2",
+ "2.11.4"
+ ),
+ // Default stage
+ scalaJSStage in Global := PreLinkStage
+ )
+
+ lazy val root: Project = Project(
+ id = "scalajs",
+ base = file("."),
+ settings = defaultSettings ++ Seq(
+ name := "Scala.js",
+ publishArtifact in Compile := false,
+
+ clean := clean.dependsOn(
+ // compiler, library and jasmineTestFramework are aggregated
+ clean in tools, clean in toolsJS, clean in plugin,
+ clean in javalanglib, clean in javalib, clean in scalalib,
+ clean in libraryAux, clean in javalibEx,
+ clean in examples, clean in helloworld,
+ clean in reversi, clean in testingExample,
+ clean in testSuite, clean in noIrCheckTest,
+ clean in javalibExTestSuite,
+ clean in partest, clean in partestSuite).value,
+
+ publish := {},
+ publishLocal := {}
+ )
+ ).aggregate(
+ compiler, library, testBridge, jasmineTestFramework
+ )
+
+ /* This project is not really used in the build. Its sources are actually
+ * added as sources of the `compiler` project (and meant to be added to the
+ * `tools` project as well).
+ * It exists mostly to be used in IDEs, because they don't like very much to
+ * have code in a project that lives outside the project's directory, and
+ * like even less that code be shared by different projects.
+ */
+ lazy val irProject: Project = Project(
+ id = "ir",
+ base = file("ir"),
+ settings = defaultSettings ++ Seq(
+ name := "Scala.js IR",
+ exportJars := true
+ )
+ )
+
+ lazy val compiler: Project = Project(
+ id = "compiler",
+ base = file("compiler"),
+ settings = defaultSettings ++ publishSettings ++ Seq(
+ name := "Scala.js compiler",
+ crossVersion := CrossVersion.full, // because compiler api is not binary compatible
+ unmanagedSourceDirectories in Compile +=
+ (scalaSource in (irProject, Compile)).value,
+ libraryDependencies ++= Seq(
+ "org.scala-lang" % "scala-compiler" % scalaVersion.value,
+ "org.scala-lang" % "scala-reflect" % scalaVersion.value,
+ "com.novocode" % "junit-interface" % "0.9" % "test"
+ ),
+ testOptions += Tests.Setup { () =>
+ val testOutDir = (streams.value.cacheDirectory / "scalajs-compiler-test")
+ IO.createDirectory(testOutDir)
+ sys.props("scala.scalajs.compiler.test.output") =
+ testOutDir.getAbsolutePath
+ sys.props("scala.scalajs.compiler.test.scalajslib") =
+ (artifactPath in (library, Compile, packageBin)).value.getAbsolutePath
+ sys.props("scala.scalajs.compiler.test.scalalib") = {
+
+ def isScalaLib(att: Attributed[File]) = {
+ att.metadata.get(moduleID.key).exists { mId =>
+ mId.organization == "org.scala-lang" &&
+ mId.name == "scala-library" &&
+ mId.revision == scalaVersion.value
+ }
+ }
+
+ val lib = (managedClasspath in Test).value.find(isScalaLib)
+ lib.map(_.data.getAbsolutePath).getOrElse {
+ streams.value.log.error("Couldn't find Scala library on the classpath. CP: " + (managedClasspath in Test).value); ""
+ }
+ }
+ },
+ exportJars := true
+ )
+ )
+
+ val commonToolsSettings = Seq(
+ name := "Scala.js tools",
+
+ unmanagedSourceDirectories in Compile ++= Seq(
+ baseDirectory.value.getParentFile / "shared/src/main/scala",
+ (scalaSource in (irProject, Compile)).value),
+
+ sourceGenerators in Compile <+= Def.task {
+ ScalaJSEnvGenerator.generateEnvHolder(
+ baseDirectory.value.getParentFile,
+ (sourceManaged in Compile).value)
+ }
+ )
+
+ lazy val tools: Project = Project(
+ id = "tools",
+ base = file("tools/jvm"),
+ settings = defaultSettings ++ publishSettings ++ (
+ commonToolsSettings
+ ) ++ Seq(
+ scalaVersion := "2.10.4",
+
+ libraryDependencies ++= Seq(
+ "com.google.javascript" % "closure-compiler" % "v20130603",
+ "com.googlecode.json-simple" % "json-simple" % "1.1.1",
+ "com.novocode" % "junit-interface" % "0.9" % "test"
+ )
+ )
+ )
+
+ lazy val toolsJS: Project = Project(
+ id = "toolsJS",
+ base = file("tools/js"),
+ settings = defaultSettings ++ myScalaJSSettings ++ publishSettings ++ (
+ commonToolsSettings
+ ) ++ Seq(
+ crossVersion := ScalaJSCrossVersion.binary
+ ) ++ inConfig(Test) {
+ // Redefine test to run Node.js and link HelloWorld
+ test := {
+ if (scalaJSStage.value == Stage.PreLink)
+ error("Can't run toolsJS/test in preLink stage")
+
+ val cp = {
+ for (e <- (fullClasspath in Test).value)
+ yield JSUtils.toJSstr(e.data.getAbsolutePath)
+ }
+
+ val runCode = """
+ var framework = org.scalajs.jasminetest.JasmineTestFramework();
+ framework.setTags("typedarray")
+
+ // Load tests
+ scalajs.TestDetector().loadDetectedTests();
+
+ var reporter = new scalajs.JasmineConsoleReporter(true);
+
+ // Setup and run Jasmine
+ var jasmineEnv = jasmine.getEnv();
+ jasmineEnv.addReporter(reporter);
+ jasmineEnv.execute();
+ """
+
+ val code = {
+ s"""
+ var lib = scalajs.QuickLinker().linkNode(${cp.mkString(", ")});
+ var run = ${JSUtils.toJSstr(runCode)};
+
+ eval("(function() { 'use strict'; "+
+ "var __ScalaJSEnv = null; " +
+ lib + "; " + run + "}).call(this);");
+ """
+ }
+
+ val launcher = new MemVirtualJSFile("Generated launcher file")
+ .withContent(code)
+
+ val runner = jsEnv.value.jsRunner(scalaJSExecClasspath.value,
+ launcher, streams.value.log, scalaJSConsole.value)
+
+ runner.run()
+ }
+ }
+ ).dependsOn(compiler % "plugin", javalibEx, testSuite % "test->test")
+
+ lazy val plugin: Project = Project(
+ id = "sbtPlugin",
+ base = file("sbt-plugin"),
+ settings = commonSettings ++ publishSettings ++ Seq(
+ name := "Scala.js sbt plugin",
+ sbtPlugin := true,
+ scalaBinaryVersion :=
+ CrossVersion.binaryScalaVersion(scalaVersion.value),
+ libraryDependencies ++= Seq(
+ "org.mozilla" % "rhino" % "1.7R4",
+ "org.webjars" % "envjs" % "1.2",
+ "com.novocode" % "junit-interface" % "0.9" % "test"
+ ) ++ ScalaJSPluginInternal.phantomJSJettyModules.map(_ % "provided")
+ )
+ ).dependsOn(tools)
+
+ lazy val delambdafySetting = {
+ scalacOptions ++= (
+ if (scalaBinaryVersion.value == "2.10") Seq()
+ else Seq("-Ydelambdafy:method"))
+ }
+
+ private def serializeHardcodedIR(base: File,
+ infoAndTree: (ir.Infos.ClassInfo, ir.Trees.ClassDef)): File = {
+ // We assume that there are no weird characters in the full name
+ val fullName = infoAndTree._1.name
+ val output = base / (fullName.replace('.', '/') + ".sjsir")
+
+ if (!output.exists()) {
+ IO.createDirectory(output.getParentFile)
+ val stream = new BufferedOutputStream(new FileOutputStream(output))
+ try {
+ ir.InfoSerializers.serialize(stream, infoAndTree._1)
+ ir.Serializers.serialize(stream, infoAndTree._2)
+ } finally {
+ stream.close()
+ }
+ }
+ output
+ }
+
+ lazy val javalanglib: Project = Project(
+ id = "javalanglib",
+ base = file("javalanglib"),
+ settings = defaultSettings ++ myScalaJSSettings ++ Seq(
+ name := "java.lang library for Scala.js",
+ publishArtifact in Compile := false,
+ delambdafySetting,
+ scalacOptions += "-Yskip:cleanup,icode,jvm",
+ scalaJSSourceMapSettings,
+ compileWithLibrarySetting,
+
+ resourceGenerators in Compile <+= Def.task {
+ val base = (resourceManaged in Compile).value
+ Seq(
+ serializeHardcodedIR(base, JavaLangObject.InfoAndTree),
+ serializeHardcodedIR(base, JavaLangString.InfoAndTree)
+ )
+ }
+ ) ++ (
+ scalaJSExternalCompileSettings
+ )
+ ).dependsOn(compiler % "plugin")
+
+ lazy val javalib: Project = Project(
+ id = "javalib",
+ base = file("javalib"),
+ settings = defaultSettings ++ myScalaJSSettings ++ Seq(
+ name := "Java library for Scala.js",
+ publishArtifact in Compile := false,
+ delambdafySetting,
+ scalacOptions += "-Yskip:cleanup,icode,jvm",
+ scalaJSSourceMapSettings,
+ compileWithLibrarySetting
+ ) ++ (
+ scalaJSExternalCompileSettings
+ )
+ ).dependsOn(compiler % "plugin")
+
+ lazy val scalalib: Project = Project(
+ id = "scalalib",
+ base = file("scalalib"),
+ settings = defaultSettings ++ myScalaJSSettings ++ Seq(
+ name := "Scala library for Scala.js",
+ publishArtifact in Compile := false,
+ delambdafySetting,
+ compileWithLibrarySetting,
+
+ // The Scala lib is full of warnings we don't want to see
+ scalacOptions ~= (_.filterNot(
+ Set("-deprecation", "-unchecked", "-feature") contains _)),
+
+
+ scalacOptions ++= List(
+ // Do not generate .class files
+ "-Yskip:cleanup,icode,jvm",
+ // Tell plugin to hack fix bad classOf trees
+ "-P:scalajs:fixClassOf",
+ // Link source maps to github sources of original Scalalib
+ "-P:scalajs:mapSourceURI:" +
+ fetchedScalaSourceDir.value.toURI +
+ "->https://raw.githubusercontent.com/scala/scala/v" +
+ scalaVersion.value + "/"
+ ),
+
+ // Link sources in override directories to our GitHub repo
+ scalaJSSourceMapSettings,
+
+ fetchedScalaSourceDir := (
+ baseDirectory.value / "fetchedSources" /
+ scalaVersion.value
+ ),
+
+ fetchScalaSource := {
+ val s = streams.value
+ val cacheDir = s.cacheDirectory
+ val ver = scalaVersion.value
+ val trgDir = fetchedScalaSourceDir.value
+
+ val report = updateClassifiers.value
+ val scalaLibSourcesJar = report.select(
+ configuration = Set("compile"),
+ module = moduleFilter(name = "scala-library"),
+ artifact = artifactFilter(`type` = "src")).headOption.getOrElse {
+ sys.error(s"Could not fetch scala-library sources for version $ver")
+ }
+
+ FileFunction.cached(cacheDir / s"fetchScalaSource-$ver",
+ FilesInfo.lastModified, FilesInfo.exists) { dependencies =>
+ s.log.info(s"Fetching Scala library sources to $trgDir...")
+
+ if (trgDir.exists)
+ IO.delete(trgDir)
+ IO.createDirectory(trgDir)
+ IO.unzip(scalaLibSourcesJar, trgDir)
+ } (Set(scalaLibSourcesJar))
+
+ trgDir
+ },
+
+ unmanagedSourceDirectories in Compile := {
+ // Calculates all prefixes of the current Scala version
+ // (including the empty prefix) to construct override
+ // directories like the following:
+ // - override-2.10.2-RC1
+ // - override-2.10.2
+ // - override-2.10
+ // - override-2
+ // - override
+ val ver = scalaVersion.value
+ val base = baseDirectory.value
+ val parts = ver.split(Array('.','-'))
+ val verList = parts.inits.map { ps =>
+ val len = ps.mkString(".").length
+ // re-read version, since we lost '.' and '-'
+ ver.substring(0, len)
+ }
+ def dirStr(v: String) =
+ if (v.isEmpty) "overrides" else s"overrides-$v"
+ val dirs = verList.map(base / dirStr(_)).filter(_.exists)
+ dirs.toSeq // most specific shadow less specific
+ },
+
+ // Compute sources
+ // Files in earlier src dirs shadow files in later dirs
+ sources in Compile := {
+ // Sources coming from the sources of Scala
+ val scalaSrcDir = fetchScalaSource.value
+
+ // All source directories (overrides shadow scalaSrcDir)
+ val sourceDirectories =
+ (unmanagedSourceDirectories in Compile).value :+ scalaSrcDir
+
+ // Filter sources with overrides
+ def normPath(f: File): String =
+ f.getPath.replace(java.io.File.separator, "/")
+
+ val sources = mutable.ListBuffer.empty[File]
+ val paths = mutable.Set.empty[String]
+
+ for {
+ srcDir <- sourceDirectories
+ normSrcDir = normPath(srcDir)
+ src <- (srcDir ** "*.scala").get
+ } {
+ val normSrc = normPath(src)
+ val path = normSrc.substring(normSrcDir.length)
+ val useless =
+ path.contains("/scala/collection/parallel/") ||
+ path.contains("/scala/util/parsing/")
+ if (!useless) {
+ if (paths.add(path))
+ sources += src
+ else
+ streams.value.log.debug(s"not including $src")
+ }
+ }
+
+ sources.result()
+ },
+
+ // Continuation plugin (when using 2.10.x)
+ autoCompilerPlugins := true,
+ libraryDependencies ++= {
+ val ver = scalaVersion.value
+ if (ver.startsWith("2.10."))
+ Seq(compilerPlugin("org.scala-lang.plugins" % "continuations" % ver))
+ else
+ Nil
+ },
+ scalacOptions ++= {
+ if (scalaVersion.value.startsWith("2.10."))
+ Seq("-P:continuations:enable")
+ else
+ Nil
+ }
+ ) ++ (
+ scalaJSExternalCompileSettings
+ )
+ ).dependsOn(compiler % "plugin")
+
+ lazy val libraryAux: Project = Project(
+ id = "libraryAux",
+ base = file("library-aux"),
+ settings = defaultSettings ++ myScalaJSSettings ++ Seq(
+ name := "Scala.js aux library",
+ publishArtifact in Compile := false,
+ delambdafySetting,
+ scalacOptions += "-Yskip:cleanup,icode,jvm",
+ scalaJSSourceMapSettings,
+ compileWithLibrarySetting
+ ) ++ (
+ scalaJSExternalCompileSettings
+ )
+ ).dependsOn(compiler % "plugin")
+
+ lazy val library: Project = Project(
+ id = "library",
+ base = file("library"),
+ settings = defaultSettings ++ publishSettings ++ myScalaJSSettings ++ Seq(
+ name := "Scala.js library",
+ delambdafySetting,
+ scalaJSSourceMapSettings,
+ scalacOptions in (Compile, doc) += "-implicits",
+ exportJars := true
+ ) ++ (
+ scalaJSExternalCompileSettings
+ ) ++ inConfig(Compile)(Seq(
+ /* Add the .sjsir files from other lib projects
+ * (but not .class files)
+ */
+ mappings in packageBin ++= {
+ val allProducts = (
+ (products in javalanglib).value ++
+ (products in javalib).value ++
+ (products in scalalib).value ++
+ (products in libraryAux).value)
+ val filter = ("*.sjsir": NameFilter)
+ allProducts.flatMap(base => Path.selectSubpaths(base, filter))
+ }
+ ))
+ ).dependsOn(compiler % "plugin")
+
+ lazy val javalibEx: Project = Project(
+ id = "javalibEx",
+ base = file("javalib-ex"),
+ settings = defaultSettings ++ publishSettings ++ myScalaJSSettings ++ Seq(
+ name := "Scala.js JavaLib Ex",
+ delambdafySetting,
+ scalacOptions += "-Yskip:cleanup,icode,jvm",
+ scalaJSSourceMapSettings,
+ exportJars := true,
+ jsDependencies +=
+ "org.webjars" % "jszip" % "2.4.0" / "jszip.min.js" commonJSName "JSZip"
+ ) ++ (
+ scalaJSExternalCompileSettings
+ )
+ ).dependsOn(compiler % "plugin", library)
+
+ lazy val stubs: Project = Project(
+ id = "stubs",
+ base = file("stubs"),
+ settings = defaultSettings ++ publishSettings ++ Seq(
+ name := "Scala.js Stubs"
+ )
+ )
+
+ // Scala.js command line interface
+ lazy val cli: Project = Project(
+ id = "cli",
+ base = file("cli"),
+ settings = defaultSettings ++ assemblySettings ++ Seq(
+ name := "Scala.js CLI",
+ scalaVersion := "2.10.4", // adapt version to tools
+ libraryDependencies ++= Seq(
+ "com.github.scopt" %% "scopt" % "3.2.0"
+ ),
+
+ // assembly options
+ mainClass in assembly := None, // don't want an executable JAR
+ assemblyOption in assembly ~= { _.copy(includeScala = false) },
+ AssemblyKeys.jarName in assembly :=
+ s"${normalizedName.value}-assembly_${scalaBinaryVersion.value}-${version.value}.jar"
+ )
+ ).dependsOn(tools)
+
+ // Test framework
+ lazy val testBridge = Project(
+ id = "testBridge",
+ base = file("test-bridge"),
+ settings = defaultSettings ++ publishSettings ++ myScalaJSSettings ++ Seq(
+ name := "Scala.js test bridge",
+ delambdafySetting,
+ scalaJSSourceMapSettings
+ )
+ ).dependsOn(compiler % "plugin", library)
+
+ lazy val jasmineTestFramework = Project(
+ id = "jasmineTestFramework",
+ base = file("jasmine-test-framework"),
+ settings = defaultSettings ++ publishSettings ++ myScalaJSSettings ++ Seq(
+ name := "Scala.js jasmine test framework",
+
+ jsDependencies ++= Seq(
+ ProvidedJS / "jasmine-polyfills.js",
+ "org.webjars" % "jasmine" % "1.3.1" /
+ "jasmine.js" dependsOn "jasmine-polyfills.js"
+ ),
+ scalaJSSourceMapSettings
+ )
+ ).dependsOn(compiler % "plugin", library, testBridge)
+
+ // Examples
+
+ lazy val examples: Project = Project(
+ id = "examples",
+ base = file("examples"),
+ settings = defaultSettings ++ Seq(
+ name := "Scala.js examples"
+ )
+ ).aggregate(helloworld, reversi, testingExample)
+
+ lazy val exampleSettings = defaultSettings ++ myScalaJSSettings
+
+ lazy val helloworld: Project = Project(
+ id = "helloworld",
+ base = file("examples") / "helloworld",
+ settings = exampleSettings ++ Seq(
+ name := "Hello World - Scala.js example",
+ moduleName := "helloworld",
+ persistLauncher := true
+ )
+ ).dependsOn(compiler % "plugin", library)
+
+ lazy val reversi = Project(
+ id = "reversi",
+ base = file("examples") / "reversi",
+ settings = exampleSettings ++ Seq(
+ name := "Reversi - Scala.js example",
+ moduleName := "reversi"
+ )
+ ).dependsOn(compiler % "plugin", library)
+
+ lazy val testingExample = Project(
+ id = "testingExample",
+ base = file("examples") / "testing",
+ settings = exampleSettings ++ Seq(
+ name := "Testing - Scala.js example",
+ moduleName := "testing",
+
+ jsDependencies ++= Seq(
+ RuntimeDOM % "test",
+ "org.webjars" % "jquery" % "1.10.2" / "jquery.js" % "test"
+ )
+ )
+ ).dependsOn(compiler % "plugin", library, jasmineTestFramework % "test")
+
+ // Testing
+
+ lazy val testSuite: Project = Project(
+ id = "testSuite",
+ base = file("test-suite"),
+ settings = defaultSettings ++ myScalaJSSettings ++ Seq(
+ name := "Scala.js test suite",
+ publishArtifact in Compile := false,
+
+ scalacOptions ~= (_.filter(_ != "-deprecation")),
+
+ sources in Test ++= {
+ if (!scalaVersion.value.startsWith("2.10") &&
+ scalacOptions.value.contains("-Xexperimental")) {
+ (((sourceDirectory in Test).value / "require-sam") ** "*.scala").get
+ } else {
+ Nil
+ }
+ },
+
+ /* Generate a scala source file that throws exceptions in
+ various places (while attaching the source line to the
+ exception). When we catch the exception, we can then
+ compare the attached source line and the source line
+ calculated via the source maps.
+
+ see test-suite/src/test/resources/SourceMapTestTemplate.scala
+ */
+ sourceGenerators in Test <+= Def.task {
+ val dir = (sourceManaged in Test).value
+ IO.createDirectory(dir)
+
+ val template = IO.read((resourceDirectory in Test).value /
+ "SourceMapTestTemplate.scala")
+
+ def lineNo(cs: CharSequence) =
+ (0 until cs.length).count(i => cs.charAt(i) == '\n') + 1
+
+ var i = 0
+ val pat = "/\\*{2,3}/".r
+ val replaced = pat.replaceAllIn(template, { mat =>
+ val lNo = lineNo(mat.before)
+ val res =
+ if (mat.end - mat.start == 5)
+ // matching a /***/
+ s"if (TC.is($i)) { throw new TestException($lNo) } else "
+ else
+ // matching a /**/
+ s"; if (TC.is($i)) { throw new TestException($lNo) } ;"
+
+ i += 1
+
+ res
+ })
+
+ val outFile = dir / "SourceMapTest.scala"
+ IO.write(outFile, replaced.replace("0/*<testCount>*/", i.toString))
+ Seq(outFile)
+ }
+ )
+ ).dependsOn(compiler % "plugin", library, jasmineTestFramework % "test")
+
+ lazy val noIrCheckTest: Project = Project(
+ id = "noIrCheckTest",
+ base = file("no-ir-check-test"),
+ settings = defaultSettings ++ myScalaJSSettings ++ Seq(
+ name := "Scala.js not IR checked tests",
+ scalaJSOptimizerOptions ~= (_.withCheckScalaJSIR(false)),
+ publishArtifact in Compile := false
+ )
+ ).dependsOn(compiler % "plugin", library, jasmineTestFramework % "test")
+
+ lazy val javalibExTestSuite: Project = Project(
+ id = "javalibExTestSuite",
+ base = file("javalib-ex-test-suite"),
+ settings = defaultSettings ++ myScalaJSSettings ++ Seq(
+ name := "JavaLib Ex Test Suite",
+ publishArtifact in Compile := false,
+
+ scalacOptions in Test ~= (_.filter(_ != "-deprecation"))
+ )
+ ).dependsOn(compiler % "plugin", javalibEx, jasmineTestFramework % "test")
+
+ lazy val partest: Project = Project(
+ id = "partest",
+ base = file("partest"),
+ settings = defaultSettings ++ Seq(
+ name := "Partest for Scala.js",
+ moduleName := "scalajs-partest",
+
+ resolvers += Resolver.typesafeIvyRepo("releases"),
+
+ fetchedScalaSourceDir := (
+ baseDirectory.value / "fetchedSources" /
+ scalaVersion.value
+ ),
+
+ fetchScalaSource := {
+ import org.eclipse.jgit.api._
+
+ val s = streams.value
+ val ver = scalaVersion.value
+ val trgDir = fetchedScalaSourceDir.value
+
+ if (!trgDir.exists) {
+ s.log.info(s"Fetching Scala source version $ver")
+
+ // Make parent dirs and stuff
+ IO.createDirectory(trgDir)
+
+ // Clone scala source code
+ new CloneCommand()
+ .setDirectory(trgDir)
+ .setURI("https://github.com/scala/scala.git")
+ .call()
+ }
+
+ // Checkout proper ref. We do this anyway so we fail if
+ // something is wrong
+ val git = Git.open(trgDir)
+ s.log.info(s"Checking out Scala source version $ver")
+ git.checkout().setName(s"v$ver").call()
+
+ trgDir
+ },
+
+ libraryDependencies ++= {
+ if (shouldPartest.value)
+ Seq(
+ "org.scala-sbt" % "sbt" % sbtVersion.value,
+ "org.scala-lang.modules" %% "scala-partest" % "1.0.1",
+ "com.google.javascript" % "closure-compiler" % "v20130603",
+ "org.mozilla" % "rhino" % "1.7R4",
+ "com.googlecode.json-simple" % "json-simple" % "1.1.1"
+ )
+ else Seq()
+ },
+
+ sources in Compile := {
+ if (shouldPartest.value) {
+ // Partest sources and some sources of sbtplugin (see above)
+ val baseSrcs = (sources in Compile).value
+ // Sources for tools (and hence IR)
+ val toolSrcs = (sources in (tools, Compile)).value
+ // Individual sources from the sbtplugin
+ val pluginSrcs = {
+ val pluginBase = ((scalaSource in (plugin, Compile)).value /
+ "scala/scalajs/sbtplugin")
+
+ val scalaFilter: FileFilter = "*.scala"
+ val files = (
+ (pluginBase * "JSUtils.scala") +++
+ (pluginBase / "env" * scalaFilter) +++
+ (pluginBase / "env" / "nodejs" ** scalaFilter) +++
+ (pluginBase / "env" / "rhino" ** scalaFilter))
+
+ files.get
+ }
+ toolSrcs ++ baseSrcs ++ pluginSrcs
+ } else Seq()
+ }
+
+ )
+ ).dependsOn(compiler)
+
+ lazy val partestSuite: Project = Project(
+ id = "partestSuite",
+ base = file("partest-suite"),
+ settings = defaultSettings ++ Seq(
+ name := "Scala.js partest suite",
+
+ fork in Test := true,
+ javaOptions in Test += "-Xmx1G",
+
+ testFrameworks ++= {
+ if (shouldPartest.value)
+ Seq(new TestFramework("scala.tools.partest.scalajs.Framework"))
+ else Seq()
+ },
+
+ definedTests in Test <++= Def.taskDyn[Seq[sbt.TestDefinition]] {
+ if (shouldPartest.value) Def.task {
+ val _ = (fetchScalaSource in partest).value
+ Seq(new sbt.TestDefinition(
+ s"partest-${scalaVersion.value}",
+ // marker fingerprint since there are no test classes
+ // to be discovered by sbt:
+ new sbt.testing.AnnotatedFingerprint {
+ def isModule = true
+ def annotationName = "partest"
+ },
+ true,
+ Array()
+ ))
+ } else {
+ Def.task(Seq())
+ }
+ }
+ )
+ ).dependsOn(partest % "test", library)
+}
diff --git a/project/build.properties b/project/build.properties
new file mode 100644
index 0000000..64abd37
--- /dev/null
+++ b/project/build.properties
@@ -0,0 +1 @@
+sbt.version=0.13.6
diff --git a/project/build.sbt b/project/build.sbt
new file mode 100644
index 0000000..b110ef2
--- /dev/null
+++ b/project/build.sbt
@@ -0,0 +1,48 @@
+resolvers += Resolver.url(
+ "bintray-sbt-plugin-releases",
+ url("http://dl.bintray.com/content/sbt/sbt-plugin-releases"))(
+ Resolver.ivyStylePatterns)
+
+addSbtPlugin("me.lessis" % "bintray-sbt" % "0.1.2")
+
+addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.11.2")
+
+libraryDependencies += "com.google.javascript" % "closure-compiler" % "v20130603"
+
+libraryDependencies += "org.mozilla" % "rhino" % "1.7R4"
+
+libraryDependencies += "org.webjars" % "envjs" % "1.2"
+
+libraryDependencies += "org.eclipse.jgit" % "org.eclipse.jgit.pgm" % "3.2.0.201312181205-r"
+
+libraryDependencies += "com.googlecode.json-simple" % "json-simple" % "1.1.1"
+
+libraryDependencies += "org.eclipse.jetty" % "jetty-websocket" % "8.1.16.v20140903"
+
+libraryDependencies += "org.eclipse.jetty" % "jetty-server" % "8.1.16.v20140903"
+
+
+unmanagedSourceDirectories in Compile ++= {
+ val root = baseDirectory.value.getParentFile
+ Seq(
+ root / "ir/src/main/scala",
+ root / "tools/shared/src/main/scala",
+ root / "tools/jvm/src/main/scala",
+ root / "sbt-plugin/src/main/scala"
+ )
+}
+
+// Add the ScalaJSEnvGenerator to the build (its in the build of the build)
+sources in Compile +=
+ baseDirectory.value / "project" / "ScalaJSEnvGenerator.scala"
+
+sourceGenerators in Compile <+= Def.task {
+ ScalaJSEnvGenerator.generateEnvHolder(
+ baseDirectory.value.getParentFile / "tools",
+ (sourceManaged in Compile).value)
+}
+
+unmanagedResourceDirectories in Compile += {
+ val root = baseDirectory.value.getParentFile
+ root / "tools/src/main/resources"
+}
diff --git a/project/project/ScalaJSEnvGenerator.scala b/project/project/ScalaJSEnvGenerator.scala
new file mode 100644
index 0000000..a36479f
--- /dev/null
+++ b/project/project/ScalaJSEnvGenerator.scala
@@ -0,0 +1,31 @@
+import sbt._
+
+object ScalaJSEnvGenerator {
+
+ /** Generate a *.scala file that contains the scalajsenv as literal string
+ *
+ * We need this so the tools don't rely on I/O and/or resources.
+ */
+ def generateEnvHolder(baseDir: File, sourceDir: File): Seq[File] = {
+ val trg = sourceDir / "ScalaJSEnvHolder.scala"
+ val env = baseDir / "scalajsenv.js"
+
+ if (!trg.exists() || trg.lastModified() < env.lastModified()) {
+ val scalajsenv = IO.read(env).replaceAllLiterally("$", "$$")
+
+ val scalaCode =
+ s"""
+ package scala.scalajs.tools.corelib
+
+ private[corelib] object ScalaJSEnvHolder {
+ final val scalajsenv = raw\"\"\"$scalajsenv\"\"\"
+ }
+ """
+
+ IO.write(trg, scalaCode)
+ }
+
+ Seq(trg)
+ }
+
+}