All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.shiftleft.js2cpg.preprocessing.TranspilingEnvironment.scala Maven / Gradle / Ivy

There is a newer version: 0.3.3
Show newest version
package io.shiftleft.js2cpg.preprocessing

import better.files.File
import io.shiftleft.js2cpg.io.ExternalCommand
import io.shiftleft.js2cpg.io.FileDefaults
import org.slf4j.LoggerFactory

import java.nio.file.Path
import scala.util.{Failure, Success}

object TranspilingEnvironment {

  val ENV_PATH_CONTENT: String = scala.util.Properties.envOrElse("PATH", "")

  // These are singleton objects because we want to check the environment only once
  // even if multiple transpilers require this specific environment:
  private var isValid: Option[Boolean]         = None
  private var isPnpmAvailable: Option[Boolean] = None
  private var isYarnAvailable: Option[Boolean] = None
  private var isNpmAvailable: Option[Boolean]  = None

  private val PNPM: String = ExternalCommand.toOSCommand("pnpm")
  private val YARN: String = ExternalCommand.toOSCommand("yarn")
  private val NPM: String  = ExternalCommand.toOSCommand("npm")

  val YARN_ADD: String =
    s"$YARN --ignore-scripts --legacy-peer-deps --dev -W add"
  val YARN_INSTALL: String =
    s"$YARN --ignore-scripts --legacy-peer-deps install"
  val PNPM_ADD: String =
    s"$PNPM --ignore-scripts add -D"
  val PNPM_INSTALL: String =
    s"$PNPM --ignore-scripts install"
  val NPM_INSTALL: String =
    s"$NPM --no-audit --progress=false --ignore-scripts --legacy-peer-deps --save-dev install"

}

trait TranspilingEnvironment {
  self: Transpiler =>

  import TranspilingEnvironment._

  private val logger = LoggerFactory.getLogger(getClass)

  object Versions {
    val babelVersions: Map[String, String] = Map(
      "@babel/core"                                        -> "7.20.2",
      "@babel/cli"                                         -> "7.19.3",
      "@babel/preset-env"                                  -> "7.20.2",
      "@babel/preset-flow"                                 -> "7.18.6",
      "@babel/preset-react"                                -> "7.18.6",
      "@babel/preset-typescript"                           -> "7.18.6",
      "@babel/plugin-proposal-class-properties"            -> "7.18.6",
      "@babel/plugin-proposal-private-methods"             -> "7.18.6",
      "@babel/plugin-proposal-private-property-in-object"  -> "7.21.11",
      "@babel/plugin-proposal-object-rest-spread"          -> "7.20.2",
      "@babel/plugin-proposal-nullish-coalescing-operator" -> "7.18.6",
      "@babel/plugin-transform-runtime"                    -> "7.19.6",
      "@babel/plugin-transform-property-mutators"          -> "7.18.6"
    )

    private val versions: Map[String, String] =
      babelVersions ++ Map("pug-cli" -> "1.0.0-alpha6", "typescript" -> "4.8.4", "@vue/cli-service-global" -> "4.5.19")

    def nameAndVersion(dependencyName: String): String = {
      if (config.fixedTranspilationDependencies) {
        val version = versions.get(dependencyName).map(v => s"@$v").getOrElse("")
        s"$dependencyName$version"
      } else {
        dependencyName
      }
    }
  }

  private def checkForPnpm(): Boolean = {
    logger.debug(s"\t+ Checking pnpm ...")
    ExternalCommand.run(s"${TranspilingEnvironment.PNPM} -v", projectPath.toString) match {
      case Success(result) =>
        logger.debug(s"\t+ pnpm is available: $result")
        true
      case Failure(_) =>
        logger.debug("\t- pnpm is not installed.")
        false
    }
  }

  private def checkForYarn(): Boolean = {
    logger.debug("\t+ Checking yarn ...")
    ExternalCommand.run(s"${TranspilingEnvironment.YARN} -v", projectPath.toString) match {
      case Success(result) =>
        logger.debug(s"\t+ yarn is available: $result")
        true
      case Failure(_) =>
        logger.debug("\t- yarn is not installed.")
        false
    }
  }

  private def checkForNpm(): Boolean = {
    logger.debug(s"\t+ Checking npm ...")
    ExternalCommand.run(s"${TranspilingEnvironment.NPM} -v", projectPath.toString) match {
      case Success(result) =>
        logger.debug(s"\t+ npm is available: $result")
        true
      case Failure(_) =>
        logger.error("\t- npm is not installed. Transpiling sources will not be available.")
        false
    }
  }

  protected def nodeVersion(): Option[String] = {
    logger.debug(s"\t+ Checking node ...")
    ExternalCommand.run("node -v", projectPath.toString) match {
      case Success(result) =>
        logger.debug(s"\t+ node is available: $result")
        Some(result)
      case Failure(_) =>
        logger.error("\t- node is not installed.")
        None
    }
  }

  protected def valid(dir: Path): Boolean = isValid match {
    case Some(value) =>
      value
    case None =>
      nodeVersion()
      isValid = Some(pnpmAvailable(dir) || yarnAvailable() || npmAvailable())
      logger.debug(s"\t+ additional node ENV settings: '${NODE_OPTIONS.mkString}'")
      isValid.get
  }

  private def anyLockFileExists(dir: Path, lockFiles: List[String]): Boolean = {
    lockFiles.exists { f =>
      val lockFile = File(dir) / f
      lockFile.exists
    }
  }

  protected def pnpmAvailable(dir: Path): Boolean = isPnpmAvailable match {
    case Some(value) =>
      val hasLockFile =
        anyLockFileExists(dir, List(FileDefaults.PNPM_LOCK_FILENAME_BAK, FileDefaults.PNPM_LOCK_FILENAME))
      value && hasLockFile
    case None =>
      val hasLockFile =
        anyLockFileExists(dir, List(FileDefaults.PNPM_LOCK_FILENAME_BAK, FileDefaults.PNPM_LOCK_FILENAME))
      isPnpmAvailable = Some(hasLockFile && checkForPnpm())
      isPnpmAvailable.get
  }

  protected def yarnAvailable(): Boolean = isYarnAvailable match {
    case Some(value) =>
      value
    case None =>
      val hasLockFile =
        anyLockFileExists(projectPath, List(FileDefaults.YARN_LOCK_FILENAME_BAK, FileDefaults.YARN_LOCK_FILENAME))
      isYarnAvailable = Some(hasLockFile && checkForYarn())
      isYarnAvailable.get
  }

  protected def npmAvailable(): Boolean = isNpmAvailable match {
    case Some(value) =>
      value
    case None =>
      isNpmAvailable = Some(checkForNpm())
      isNpmAvailable.get
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy