Skip to content

Commit

Permalink
Extract ImportTypings
Browse files Browse the repository at this point in the history
Extract part of ImportTypings as ImportTypingsUtil in importer-portable.
  • Loading branch information
andrelfpinto committed Apr 16, 2024
1 parent 1516acf commit d572f30
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 120 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package org.scalablytyped.converter
package internal

import java.nio.file.Path

import com.olvind.logging.Logger
import io.circe013.{Decoder, Encoder}
import org.scalablytyped.converter.internal.importer._
import org.scalablytyped.converter.internal.importer.build.{Compiler, IvyLayout, PublishedSbtProject}
import org.scalablytyped.converter.internal.importer.documentation.Npmjs
import org.scalablytyped.converter.internal.maps._
import org.scalablytyped.converter.internal.phases.{PhaseListener, PhaseRes, PhaseRunner, RecPhase}
import org.scalablytyped.converter.internal.scalajs.Dep
import org.scalablytyped.converter.internal.ts._
import os.RelPath

import scala.collection.immutable.SortedMap

object ImportTypingsUtil {
case class Input(
converterVersion: String,
conversion: ConversionOptions,
wantedLibs: SortedMap[TsIdentLibrary, String],
) {
lazy val packageJsonHash: String =
Digest.of(IArray.fromTraversable(wantedLibs.map { case (name, v) => s"${name.value} $v" })).hexString
}

object Input {
implicit val encodes: Encoder[Input] = io.circe013.generic.semiauto.deriveEncoder
implicit val decodes: Decoder[Input] = io.circe013.generic.semiauto.deriveDecoder
}

type Results = Map[LibTsSource, PhaseRes[LibTsSource, PublishedSbtProject]]
type Successes = Map[LibTsSource, PublishedSbtProject]
type Failures = Map[LibTsSource, Either[Throwable, String]]

def get(
input: Input,
logger: Logger[Unit],
parseCacheDirOpt: Option[Path],
publishLocalFolder: os.Path,
fromFolder: InFolder,
targetFolder: os.Path,
compiler: Compiler,
includeProject: Boolean = false,
): (Results, Successes, Failures) = {
if (input.conversion.expandTypeMappings =/= EnabledTypeMappingExpansion.DefaultSelection) {
logger.warn("Changing stInternalExpandTypeMappings not encouraged. It might blow up")
}

if (input.conversion.enableLongApplyMethod) {
logger.warn("enableLongApplyMethod is deprecated and untested. You should migrate to the builder pattern.")
}

val bootstrapped = Bootstrap.fromNodeModules(fromFolder, input.conversion, input.wantedLibs.keySet)

val inDir = fromFolder.path / os.up

val projectSource: Option[LibTsSource.FromFolder] =
if (includeProject) Some(LibTsSource.FromFolder(InFolder(inDir), TsIdentLibrary(inDir.last))) else None

val sources: Vector[LibTsSource] = {
bootstrapped.initialLibs match {
case Left(unresolved) => sys.error(unresolved.msg)
case Right(initial) => projectSource.foldLeft(initial)(_ :+ _)
}
}

logger.info(s"Importing ${sources.map(_.libName.value).mkString(", ")}")

val cachedParser = PersistingParser(parseCacheDirOpt, bootstrapped.inputFolders, logger)

val Phases: RecPhase[LibTsSource, PublishedSbtProject] = RecPhase[LibTsSource]
.next(
new Phase1ReadTypescript(
resolve = bootstrapped.libraryResolver,
calculateLibraryVersion = CalculateLibraryVersion.PackageJsonOnly,
ignored = input.conversion.ignoredLibs,
ignoredModulePrefixes = input.conversion.ignoredModulePrefixes,
pedantic = false,
parser = cachedParser,
expandTypeMappings = input.conversion.expandTypeMappings,
),
"typescript",
)
.next(
new Phase2ToScalaJs(
pedantic = false,
scalaVersion = input.conversion.versions.scala,
enableScalaJsDefined = input.conversion.enableScalaJsDefined,
outputPkg = input.conversion.outputPackage,
flavour = input.conversion.flavourImpl,
useDeprecatedModuleNames = input.conversion.useDeprecatedModuleNames,
),
"scala.js",
)
.next(
new PhaseFlavour(input.conversion.flavourImpl, maybePrivateWithin = input.conversion.privateWithin),
input.conversion.flavourImpl.toString,
)
.next(
new Phase3Compile(
versions = input.conversion.versions,
compiler = compiler,
targetFolder = targetFolder,
organization = input.conversion.organization,
publishLocalFolder = publishLocalFolder,
metadataFetcher = Npmjs.No,
softWrites = true,
flavour = input.conversion.flavourImpl,
generateScalaJsBundlerFile = false,
ensureSourceFilesWritten = false,
),
"build",
)

val results: Results =
sources
.map(s => (s: LibTsSource) -> PhaseRunner(Phases, (_: LibTsSource) => logger, PhaseListener.NoListener)(s))
.toMap
.toSorted

val successes: Successes = {
def go(source: LibTsSource, p: PublishedSbtProject): Successes =
Map(source -> p) ++ p.project.deps.flatMap { case (k, v) => go(k, v) }

results.collect { case (s, PhaseRes.Ok(res)) => go(s, res) }.reduceOption(_ ++ _).getOrElse(Map.empty)
}

val failures: Failures =
results.collect { case (_, PhaseRes.Failure(errors)) => errors }.reduceOption(_ ++ _).getOrElse(Map.empty)

(results, successes, failures)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import java.nio.file.Path
import com.olvind.logging.Logger
import io.circe013.{Decoder, Encoder}
import org.scalablytyped.converter.internal.importer._
import org.scalablytyped.converter.internal.ImportTypingsUtil.{Failures, Results, Successes}
import org.scalablytyped.converter.internal.importer.build.{Compiler, IvyLayout, PublishedSbtProject}
import org.scalablytyped.converter.internal.importer.documentation.Npmjs
import org.scalablytyped.converter.internal.maps._
Expand All @@ -18,22 +19,9 @@ import sbt.librarymanagement.ModuleID
import scala.collection.immutable.SortedMap

object ImportTypings {
type Input = ImportTypingsUtil.Input
type InOut = (Input, Output)

case class Input(
converterVersion: String,
conversion: ConversionOptions,
wantedLibs: SortedMap[TsIdentLibrary, String],
) {
lazy val packageJsonHash: String =
Digest.of(IArray.fromTraversable(wantedLibs.map { case (name, v) => s"${name.value} $v" })).hexString
}

object Input {
implicit val encodes: Encoder[Input] = io.circe013.generic.semiauto.deriveEncoder
implicit val decodes: Decoder[Input] = io.circe013.generic.semiauto.deriveDecoder
}

case class Output(externalDeps: Set[Dep.Concrete], allProjects: IArray[Dep.Concrete]) {
val allRelPaths: IArray[RelPath] =
allProjects.flatMap(p => IvyLayout.unit(p).all.map { case (k, _) => k })
Expand All @@ -47,109 +35,6 @@ object ImportTypings {
implicit val decodes: Decoder[Output] = io.circe013.generic.semiauto.deriveDecoder
}

type Results = Map[LibTsSource, PhaseRes[LibTsSource, PublishedSbtProject]]
type Successes = Map[LibTsSource, PublishedSbtProject]
type Failures = Map[LibTsSource, Either[Throwable, String]]

def get(
input: Input,
logger: Logger[Unit],
parseCacheDirOpt: Option[Path],
publishLocalFolder: os.Path,
fromFolder: InFolder,
targetFolder: os.Path,
compiler: Compiler,
includeProject: Boolean = false,
): (Results, Successes, Failures) = {
if (input.conversion.expandTypeMappings =/= EnabledTypeMappingExpansion.DefaultSelection) {
logger.warn("Changing stInternalExpandTypeMappings not encouraged. It might blow up")
}

if (input.conversion.enableLongApplyMethod) {
logger.warn("enableLongApplyMethod is deprecated and untested. You should migrate to the builder pattern.")
}

val bootstrapped = Bootstrap.fromNodeModules(fromFolder, input.conversion, input.wantedLibs.keySet)

val inDir = fromFolder.path / os.up

val projectSource: Option[LibTsSource.FromFolder] =
if (includeProject) Some(LibTsSource.FromFolder(InFolder(inDir), TsIdentLibrary(inDir.last))) else None

val sources: Vector[LibTsSource] = {
bootstrapped.initialLibs match {
case Left(unresolved) => sys.error(unresolved.msg)
case Right(initial) => projectSource.foldLeft(initial)(_ :+ _)
}
}

logger.info(s"Importing ${sources.map(_.libName.value).mkString(", ")}")

val cachedParser = PersistingParser(parseCacheDirOpt, bootstrapped.inputFolders, logger)

val Phases: RecPhase[LibTsSource, PublishedSbtProject] = RecPhase[LibTsSource]
.next(
new Phase1ReadTypescript(
resolve = bootstrapped.libraryResolver,
calculateLibraryVersion = CalculateLibraryVersion.PackageJsonOnly,
ignored = input.conversion.ignoredLibs,
ignoredModulePrefixes = input.conversion.ignoredModulePrefixes,
pedantic = false,
parser = cachedParser,
expandTypeMappings = input.conversion.expandTypeMappings,
),
"typescript",
)
.next(
new Phase2ToScalaJs(
pedantic = false,
scalaVersion = input.conversion.versions.scala,
enableScalaJsDefined = input.conversion.enableScalaJsDefined,
outputPkg = input.conversion.outputPackage,
flavour = input.conversion.flavourImpl,
useDeprecatedModuleNames = input.conversion.useDeprecatedModuleNames,
),
"scala.js",
)
.next(
new PhaseFlavour(input.conversion.flavourImpl, maybePrivateWithin = input.conversion.privateWithin),
input.conversion.flavourImpl.toString,
)
.next(
new Phase3Compile(
versions = input.conversion.versions,
compiler = compiler,
targetFolder = targetFolder,
organization = input.conversion.organization,
publishLocalFolder = publishLocalFolder,
metadataFetcher = Npmjs.No,
softWrites = true,
flavour = input.conversion.flavourImpl,
generateScalaJsBundlerFile = false,
ensureSourceFilesWritten = false,
),
"build",
)

val results: Results =
sources
.map(s => (s: LibTsSource) -> PhaseRunner(Phases, (_: LibTsSource) => logger, PhaseListener.NoListener)(s))
.toMap
.toSorted

val successes: Successes = {
def go(source: LibTsSource, p: PublishedSbtProject): Successes =
Map(source -> p) ++ p.project.deps.flatMap { case (k, v) => go(k, v) }

results.collect { case (s, PhaseRes.Ok(res)) => go(s, res) }.reduceOption(_ ++ _).getOrElse(Map.empty)
}

val failures: Failures =
results.collect { case (_, PhaseRes.Failure(errors)) => errors }.reduceOption(_ ++ _).getOrElse(Map.empty)

(results, successes, failures)
}

def apply(
input: Input,
logger: Logger[Unit],
Expand All @@ -161,7 +46,7 @@ object ImportTypings {
): Either[Failures, Output] = {

val (_, successes, failures) =
get(input, logger, parseCacheDirOpt, publishLocalFolder, fromFolder, targetFolder, compiler)
ImportTypingsUtil.get(input, logger, parseCacheDirOpt, publishLocalFolder, fromFolder, targetFolder, compiler)

if (failures.nonEmpty) Left(failures)
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ object ScalablyTypedConverterExternalNpmPlugin extends AutoPlugin {

val conversion = stConversionOptions.value

val input = ImportTypings.Input(
val input = new ImportTypings.Input(
converterVersion = BuildInfo.version,
conversion = conversion,
wantedLibs = wantedLibs,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ object ScalablyTypedConverterPlugin extends AutoPlugin {
val fromFolder = InFolder(os.Path((Compile / npmUpdate / Keys.crossTarget).value / "node_modules"))
val targetFolder = os.Path(Keys.streams.value.cacheDirectory) / "sources"

val input = ImportTypings.Input(
val input = new ImportTypings.Input(
converterVersion = BuildInfo.version,
conversion = conversion,
wantedLibs = WantedLibs.setting.value,
Expand Down

0 comments on commit d572f30

Please sign in to comment.