Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
49 changed files
with
1,942 additions
and
631 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
68 changes: 68 additions & 0 deletions
68
linker-interface/shared/src/main/scala/org/scalajs/linker/interface/LinkerCompat.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
/* | ||
* Scala.js (https://www.scala-js.org/) | ||
* | ||
* Copyright EPFL. | ||
* | ||
* Licensed under Apache License 2.0 | ||
* (https://www.apache.org/licenses/LICENSE-2.0). | ||
* | ||
* See the NOTICE file distributed with this work for | ||
* additional information regarding copyright ownership. | ||
*/ | ||
|
||
package org.scalajs.linker.interface | ||
|
||
import scala.concurrent._ | ||
|
||
import java.nio.ByteBuffer | ||
|
||
import org.scalajs.linker.interface.unstable.{OutputFileImpl, OutputDirectoryImpl} | ||
|
||
private[linker] object LinkerCompat { | ||
def linkerOutputToOutputSpec( | ||
output: LinkerOutput, moduleID: ModuleSpec.ModuleID): OutputSpec = { | ||
|
||
val jsFileImpl = OutputFileImpl.fromOutputFile(output.jsFile) | ||
|
||
val jsFileName = | ||
output.jsFileURI.fold(jsFileImpl.name)(_.toASCIIString) | ||
|
||
val sourceMapFileImpl = | ||
output.sourceMap.map(OutputFileImpl.fromOutputFile(_)) | ||
|
||
val sourceMapName = output.sourceMapURI | ||
.map(_.toASCIIString) | ||
.orElse(sourceMapFileImpl.map(_.name)) | ||
.getOrElse(jsFileName + ".map") | ||
|
||
require(jsFileName != sourceMapName, | ||
"Could not determine different names for the source map and the JS file.") | ||
|
||
def selectFile(name: String): OutputFileImpl = name match { | ||
case `jsFileName` => jsFileImpl | ||
|
||
case `sourceMapName` => | ||
sourceMapFileImpl.getOrElse { | ||
throw new IllegalArgumentException("The linker tried to write a " + | ||
"source map, but none was provided in an adapted LinkerOutput. " + | ||
"This is not supported.") | ||
} | ||
|
||
case _ => | ||
throw new IllegalArgumentException("The linker tried to write to a file " + | ||
"name not provided by the adapter.") | ||
} | ||
|
||
val outputDirectory = new OutputDirectoryImpl { | ||
def newChannel(name: String)(implicit ec: ExecutionContext): Future[OutputDirectoryImpl.Channel] = | ||
selectFile(name).newChannel() | ||
|
||
override def writeFull(name: String, buf: ByteBuffer)(implicit ec: ExecutionContext): Future[Unit] = | ||
selectFile(name).writeFull(buf) | ||
} | ||
|
||
OutputSpec(outputDirectory) | ||
.withJSName(_ => jsFileName) | ||
.withSourceMapName(_ => sourceMapName) | ||
} | ||
} |
77 changes: 77 additions & 0 deletions
77
linker-interface/shared/src/main/scala/org/scalajs/linker/interface/ModuleSpec.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
/* | ||
* Scala.js (https://www.scala-js.org/) | ||
* | ||
* Copyright EPFL. | ||
* | ||
* Licensed under Apache License 2.0 | ||
* (https://www.apache.org/licenses/LICENSE-2.0). | ||
* | ||
* See the NOTICE file distributed with this work for | ||
* additional information regarding copyright ownership. | ||
*/ | ||
|
||
package org.scalajs.linker.interface | ||
|
||
import org.scalajs.linker.interface.unstable.ModuleSpecImpl.SelectorImpl | ||
|
||
/** Module output specification. */ | ||
final class ModuleSpec ( | ||
val id: ModuleSpec.ModuleID, | ||
val selector: ModuleSpec.Selector, | ||
val initializers: Seq[ModuleInitializer], | ||
) { | ||
private def this(id: ModuleSpec.ModuleID) = | ||
this(id, ModuleSpec.Selector.empty, Nil) | ||
|
||
def withID(id: ModuleSpec.ModuleID): ModuleSpec = | ||
copy(id = id) | ||
|
||
def withSelector(selector: ModuleSpec.Selector): ModuleSpec = | ||
copy(selector = selector) | ||
|
||
def withInitializers(initializers: Seq[ModuleInitializer]): ModuleSpec = | ||
copy(initializers = initializers) | ||
|
||
private def copy( | ||
id: ModuleSpec.ModuleID = id, | ||
selector: ModuleSpec.Selector = selector, | ||
initializers: Seq[ModuleInitializer] = initializers): ModuleSpec = { | ||
new ModuleSpec(id, selector, initializers) | ||
} | ||
} | ||
|
||
object ModuleSpec { | ||
final class ModuleID(val id: String) extends AnyVal | ||
|
||
def apply(id: String): ModuleSpec = | ||
new ModuleSpec(new ModuleID(id)) | ||
|
||
def validate(moduleSpec: List[ModuleSpec]): Unit = { | ||
??? | ||
} | ||
|
||
final class Selector private ( | ||
private[interface] val impls: List[SelectorImpl]) { | ||
def ++(that: Selector): Selector = | ||
new Selector(this.impls ++ that.impls) | ||
} | ||
|
||
object Selector { | ||
import SelectorImpl._ | ||
|
||
def empty: Selector = | ||
new Selector(Nil) | ||
|
||
def default: Selector = | ||
new Selector(Default :: Nil) | ||
|
||
def packageName(name: String): Selector = | ||
new Selector(PackageName(name) :: Nil) | ||
|
||
def className(name: String): Selector = | ||
new Selector(ClassName(name) :: Nil) | ||
|
||
def exportName(name: String): Selector = | ||
new Selector(ExportName(name) :: Nil) | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
linker-interface/shared/src/main/scala/org/scalajs/linker/interface/OutputDirectory.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
/* | ||
* Scala.js (https://www.scala-js.org/) | ||
* | ||
* Copyright EPFL. | ||
* | ||
* Licensed under Apache License 2.0 | ||
* (https://www.apache.org/licenses/LICENSE-2.0). | ||
* | ||
* See the NOTICE file distributed with this work for | ||
* additional information regarding copyright ownership. | ||
*/ | ||
|
||
package org.scalajs.linker.interface | ||
|
||
import org.scalajs.linker.interface.unstable.OutputDirectoryImpl | ||
|
||
/** Directory where the linker will write its output files. */ | ||
abstract class OutputDirectory private[interface] () { | ||
private[interface] def impl: OutputDirectoryImpl | ||
} |
43 changes: 43 additions & 0 deletions
43
linker-interface/shared/src/main/scala/org/scalajs/linker/interface/OutputSpec.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
/* | ||
* Scala.js (https://www.scala-js.org/) | ||
* | ||
* Copyright EPFL. | ||
* | ||
* Licensed under Apache License 2.0 | ||
* (https://www.apache.org/licenses/LICENSE-2.0). | ||
* | ||
* See the NOTICE file distributed with this work for | ||
* additional information regarding copyright ownership. | ||
*/ | ||
|
||
package org.scalajs.linker.interface | ||
|
||
final class OutputSpec private ( | ||
val directory: OutputDirectory, | ||
val jsName: ModuleSpec.ModuleID => String, | ||
val sourceMapName: ModuleSpec.ModuleID => String, | ||
) { | ||
def this(directory: OutputDirectory) = | ||
this(directory, _.id + ".js", _.id + ".js.map") | ||
|
||
def withDirectory(directory: OutputDirectory): OutputSpec = | ||
copy(directory = directory) | ||
|
||
def withJSName(jsName: ModuleSpec.ModuleID => String): OutputSpec = | ||
copy(jsName = jsName) | ||
|
||
def withSourceMapName(sourceMapName: ModuleSpec.ModuleID => String): OutputSpec = | ||
copy(sourceMapName = sourceMapName) | ||
|
||
private def copy( | ||
directory: OutputDirectory = directory, | ||
jsName: ModuleSpec.ModuleID => String = jsName, | ||
sourceMapName: ModuleSpec.ModuleID => String = sourceMapName): OutputSpec = { | ||
new OutputSpec(directory, jsName, sourceMapName) | ||
} | ||
} | ||
|
||
object OutputSpec { | ||
def apply(directory: OutputDirectory): OutputSpec = | ||
new OutputSpec(directory) | ||
} |
46 changes: 46 additions & 0 deletions
46
...nterface/shared/src/main/scala/org/scalajs/linker/interface/unstable/ModuleSpecImpl.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
/* | ||
* Scala.js (https://www.scala-js.org/) | ||
* | ||
* Copyright EPFL. | ||
* | ||
* Licensed under Apache License 2.0 | ||
* (https://www.apache.org/licenses/LICENSE-2.0). | ||
* | ||
* See the NOTICE file distributed with this work for | ||
* additional information regarding copyright ownership. | ||
*/ | ||
|
||
package org.scalajs.linker.interface.unstable | ||
|
||
import org.scalajs.linker.interface.ModuleSpec | ||
|
||
object ModuleSpecImpl { | ||
sealed abstract class SelectorImpl(private[ModuleSpecImpl] val precedence: Int) | ||
|
||
object SelectorImpl { | ||
// TODO: Validate that names are correct. | ||
final case class ExportName(name: String) extends SelectorImpl(1) | ||
final case class ClassName(name: String) extends SelectorImpl(2) | ||
final case class PackageName(name: String) extends SelectorImpl(3) | ||
final case object Default extends SelectorImpl(4) | ||
} | ||
|
||
def compileSelectors(moduleSpecs: List[ModuleSpec]): Seq[(SelectorImpl, ModuleSpec.ModuleID)] = { | ||
val selectors = for { | ||
moduleSpec <- moduleSpecs | ||
selectorImpl <- moduleSpec.selector.impls | ||
} yield (selectorImpl, moduleSpec.id) | ||
|
||
// Check for duplicates. | ||
for { | ||
(selector, pairs) <- selectors.groupBy(_._1) | ||
if pairs.size > 1 | ||
} { | ||
val ids = pairs.map(_._2.id).mkString(", ") | ||
throw new IllegalArgumentException( | ||
s"Module selector $selector appears multiple times (in modules $ids)") | ||
} | ||
|
||
selectors.sortBy(_._1.precedence) | ||
} | ||
} |
59 changes: 59 additions & 0 deletions
59
...ace/shared/src/main/scala/org/scalajs/linker/interface/unstable/OutputDirectoryImpl.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
/* | ||
* Scala.js (https://www.scala-js.org/) | ||
* | ||
* Copyright EPFL. | ||
* | ||
* Licensed under Apache License 2.0 | ||
* (https://www.apache.org/licenses/LICENSE-2.0). | ||
* | ||
* See the NOTICE file distributed with this work for | ||
* additional information regarding copyright ownership. | ||
*/ | ||
|
||
package org.scalajs.linker.interface.unstable | ||
|
||
import scala.concurrent._ | ||
|
||
import java.nio.ByteBuffer | ||
|
||
import org.scalajs.linker.interface.OutputDirectory | ||
|
||
abstract class OutputDirectoryImpl extends OutputDirectory { | ||
final private[interface] def impl: OutputDirectoryImpl = this | ||
|
||
def newChannel(name: String)( | ||
implicit ec: ExecutionContext): Future[OutputDirectoryImpl.Channel] | ||
|
||
def writeFull(name: String, buf: ByteBuffer)( | ||
implicit ec: ExecutionContext): Future[Unit] = { | ||
newChannel(name).flatMap { chan => | ||
def writeLoop(): Future[Unit] = { | ||
if (buf.hasRemaining()) chan.write(buf).flatMap(_ => writeLoop()) | ||
else Future.successful(()) | ||
} | ||
|
||
finallyWith(writeLoop(), chan.close()) | ||
} | ||
} | ||
|
||
private def finallyWith(v: Future[Unit], f: => Future[Unit])( | ||
implicit ec: ExecutionContext): Future[Unit] = { | ||
v.map[Option[Throwable]](_ => None) | ||
.recover { case t => Some(t) } | ||
.flatMap { | ||
case None => f | ||
|
||
case Some(vt) => | ||
f.transform(_ => throw vt, ft => { ft.addSuppressed(vt); ft }) | ||
} | ||
} | ||
} | ||
|
||
object OutputDirectoryImpl { | ||
def fromOutputDirectory(f: OutputDirectory): OutputDirectoryImpl = f.impl | ||
|
||
trait Channel { | ||
def write(buf: ByteBuffer)(implicit ec: ExecutionContext): Future[Unit] | ||
def close()(implicit ec: ExecutionContext): Future[Unit] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.