Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 10 additions & 3 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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/")),
Expand Down
17 changes: 15 additions & 2 deletions scripts/test-cli.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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 <<EOF
asdf 2
EOF

diff got-legacy.run want-legacy.run

mkdir test-output
scalajsld -s --outputDir test-output --moduleSplitStyle SmallestModules --moduleKind CommonJSModule -mm Foo.main bin
test "$(ls test-output/*.js| wc -w)" -gt "1" || fail "scalajsld: produced single js output file"

node test-output/main.js > got.run
cat > want.run <<EOF
asdf 2
EOF
Expand Down
100 changes: 81 additions & 19 deletions src/main/scala/org/scalajs/cli/Scalajsld.scala
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,13 @@ object Scalajsld {
private case class Options(
cp: Seq[File] = Seq.empty,
moduleInitializers: Seq[ModuleInitializer] = Seq.empty,
output: File = null,
output: Option[File] = None,
outputDir: Option[File] = None,
semantics: Semantics = Semantics.Defaults,
esFeatures: ESFeatures = ESFeatures.Defaults,
moduleKind: ModuleKind = ModuleKind.NoModule,
moduleSplitStyle: ModuleSplitStyle = ModuleSplitStyle.FewestModules,
outputPatterns: OutputPatterns = OutputPatterns.Defaults,
noOpt: Boolean = false,
fullOpt: Boolean = false,
prettyPrint: Boolean = false,
Expand Down Expand Up @@ -66,6 +69,15 @@ object Scalajsld {
}
}

private implicit object ModuleSplitStyleRead extends scopt.Read[ModuleSplitStyle] {
val All = List(ModuleSplitStyle.FewestModules, ModuleSplitStyle.SmallestModules)
val arity = 1
val reads = { (s: String) =>
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)
Expand All @@ -81,15 +93,26 @@ object Scalajsld {
.text("Execute the specified main(Array[String]) method on startup")
opt[File]('o', "output")
.valueName("<file>")
.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("<dir>")
.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)")
Expand Down Expand Up @@ -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
}
Expand All @@ -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)
Expand All @@ -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)
}
}
}