refactor(js): NPM modules resolution (#722)

Refactored NPM modules resolution
This commit is contained in:
InversionSpaces 2023-05-31 12:00:13 +02:00 committed by GitHub
parent 19c4e509a8
commit df19ec6734
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 52 additions and 43 deletions

View File

@ -2,7 +2,7 @@ package aqua
import cats.effect.kernel.Async
import fs2.io.file.{Files, Path}
import aqua.js.{Meta, Module}
import aqua.js.Npm
import scribe.Logging
import cats.syntax.applicative.*
import cats.syntax.apply.*
@ -14,44 +14,44 @@ import scala.util.Try
object PlatformPackagePath extends Logging {
// get path of nth parent strictly
private def parentStrict(n: Int)(path: Path): Option[Path] =
if (n <= 0) Some(path)
else (0 until n).foldLeft(Option(path))((p, _) => p.flatMap(_.parent))
// get path of nth parent relatively
private def parentRelative(n: Int)(path: Path): Path =
if (n <= 0) path
else path.resolve((0 until n).map(_ => "../").mkString)
// could throw an error
private def builtinPath = Path(Npm.resolveModule("@fluencelabs/aqua-lib/builtin.aqua"))
// it could be global installed aqua and local installed, different paths for this
def getPackagePath[F[_]: Async](path: String): F[Path] = {
val meta = Meta.metaUrl
val req = Module.createRequire(meta)
Try {
// this can throw an error, global or local project path
val builtinPath = Path(req.resolve("@fluencelabs/aqua-lib/builtin.aqua").toString)
val rootProjectPath = builtinPath.resolve("../../../..")
def getPackagePath[F[_]: Async](path: String): F[Path] = Try {
val rootProjectPath = parentRelative(4)(builtinPath)
// hack, check if it is a local dependency or global
val filePath = rootProjectPath.resolve(path)
Files[F].exists(filePath).map {
// if not exists, it should be local dependency, check in node_modules
case false => rootProjectPath.resolve("node_modules/@fluencelabs/aqua").resolve(path)
case true => filePath
}
}.getOrElse {
// we don't care about path if there is no builtins, but must write an error
logger.error("Unexpected. Cannot find project path")
Path(path).pure[F]
}
}
// get path to node modules if there is `aqua-lib` module with `builtin.aqua` in it
def getGlobalNodeModulePath: List[Path] = {
val meta = Meta.metaUrl
val req = Module.createRequire(meta)
Try {
// this can throw an error
val pathStr = req.resolve("@fluencelabs/aqua-lib/builtin.aqua").toString
def getGlobalNodeModulePath: List[Path] = Try {
// hack
val globalAquaPath = Path(pathStr).parent.flatMap(_.parent.flatMap(_.parent))
val globalAquaPath = parentStrict(3)(builtinPath)
// Also hack. If we found installed `aqua-lib`, it should be in `node_modules` global path.
// In global `node_modules` could be installed aqua libs and we must use them,
// if they were imported in aqua files
val globalNodeModulesPath =
globalAquaPath.flatMap(_.parent.flatMap(_.parent.flatMap(_.parent)))
val globalNodeModulesPath = globalAquaPath.flatMap(parentStrict(3))
globalAquaPath.toList ++ globalNodeModulesPath.toList
}.getOrElse {
@ -61,4 +61,3 @@ object PlatformPackagePath extends Logging {
}
}
}

View File

@ -12,14 +12,24 @@ object Meta {
val metaUrl: String = js.native
}
// Require function from javascript
trait Require extends js.Object {
// resolve path to module
def resolve(request: String): String
}
@js.native
@JSImport("module", JSImport.Namespace)
object Module extends js.Object {
// make it possible to use `require` in ES module type
def createRequire(str: String): Require = js.native
def createRequire(filename: String): Require = js.native
}
trait Require extends js.Object {
def resolve(str: String): Any
object Npm {
private def require = Module.createRequire(Meta.metaUrl)
// Resolve path to module
def resolveModule(path: String): String = require.resolve(path)
}