@@ -4,31 +4,58 @@ import better.files.File
44import io .shiftleft .js2cpg .core .Config
55import io .shiftleft .js2cpg .io .ExternalCommand
66import io .shiftleft .js2cpg .io .FileDefaults
7- import io .shiftleft .js2cpg .io .FileDefaults .VUE_SUFFIX
7+ import io .shiftleft .js2cpg .io .FileDefaults ._
88import io .shiftleft .js2cpg .io .FileUtils
99import io .shiftleft .js2cpg .parser .PackageJsonParser
1010import org .slf4j .LoggerFactory
1111
1212import java .nio .file .{Path , Paths }
1313import scala .util .{Failure , Success }
14+ import scala .util .Try
1415
1516object VueTranspiler {
1617
18+ private val BrowsersListRc : String = " .browserslistrc"
19+ private val VueConfigJs : String = " vue.config.js"
20+ private val Vue2Config : String =
21+ """
22+ |module.exports = {
23+ | configureWebpack: {
24+ | devtool: 'source-map'
25+ | }
26+ |}
27+ |""" .stripMargin
28+ private val Vue3Config : String =
29+ """
30+ |const { defineConfig } = require('@vue/cli-service');
31+ |module.exports = defineConfig({
32+ | configureWebpack: {
33+ | devtool: 'source-map',
34+ | }
35+ |});
36+ |""" .stripMargin
37+
1738 private def hasVueFiles (config : Config , projectPath : Path ): Boolean =
1839 FileUtils .getFileTree(projectPath, config, List (VUE_SUFFIX )).nonEmpty
1940
2041 def isVueProject (config : Config , projectPath : Path ): Boolean = {
2142 val hasVueDep =
22- PackageJsonParser
23- .dependencies((File (config.srcDir) / FileDefaults .PACKAGE_JSON_FILENAME ).path)
24- .contains(" vue" )
43+ PackageJsonParser .dependencies((File (config.srcDir) / FileDefaults .PACKAGE_JSON_FILENAME ).path).contains(" vue" )
2544 hasVueDep && hasVueFiles(config, projectPath)
2645 }
46+
47+ private def vueVersion (config : Config ): Int = {
48+ val versionString =
49+ PackageJsonParser .dependencies((File (config.srcDir) / FileDefaults .PACKAGE_JSON_FILENAME ).path)(" vue" )
50+ // ignore ~, ^, and more from semver; see: https://stackoverflow.com/a/25861938
51+ val c = versionString.collectFirst { case c if Try (c.toString.toInt).isSuccess => c.toString.toInt }
52+ c.getOrElse(3 ) // 3 is the latest version; we default to that
53+ }
2754}
2855
2956class VueTranspiler (override val config : Config , override val projectPath : Path ) extends Transpiler {
3057
31- import VueTranspiler .isVueProject
58+ import VueTranspiler ._
3259
3360 private val logger = LoggerFactory .getLogger(getClass)
3461
@@ -48,13 +75,17 @@ class VueTranspiler(override val config: Config, override val projectPath: Path)
4875 }
4976 }
5077
78+ private def hasTsFiles : Boolean =
79+ FileUtils .getFileTree(projectPath, config, List (TS_SUFFIX )).nonEmpty
80+
5181 private def installVuePlugins (): Boolean = {
82+ val additionalPlugins = if (hasTsFiles) " typescript @vue/cli-plugin-typescript" else " "
5283 val command = if (pnpmAvailable(projectPath)) {
53- s " ${TranspilingEnvironment .PNPM_ADD } $vueAndVersion && ${TranspilingEnvironment .PNPM_INSTALL }"
84+ s " ${TranspilingEnvironment .PNPM_ADD } $vueAndVersion $additionalPlugins && ${TranspilingEnvironment .PNPM_INSTALL }"
5485 } else if (yarnAvailable()) {
55- s " ${TranspilingEnvironment .YARN_ADD } $vueAndVersion && ${TranspilingEnvironment .YARN_INSTALL }"
86+ s " ${TranspilingEnvironment .YARN_ADD } $vueAndVersion $additionalPlugins && ${TranspilingEnvironment .YARN_INSTALL }"
5687 } else {
57- s " ${TranspilingEnvironment .NPM_INSTALL } $vueAndVersion"
88+ s " ${TranspilingEnvironment .NPM_INSTALL } $vueAndVersion $additionalPlugins "
5889 }
5990 logger.info(" Installing Vue.js dependencies and plugins. That will take a while." )
6091 logger.debug(s " \t + Installing Vue.js plugins with command ' $command' in path ' $projectPath' " )
@@ -69,20 +100,29 @@ class VueTranspiler(override val config: Config, override val projectPath: Path)
69100 }
70101
71102 private def createCustomBrowserslistFile (): Unit = {
72- val browserslistFile = File (projectPath) / " .browserslistrc"
73- if (browserslistFile.exists) {
74- browserslistFile.delete(swallowIOExceptions = true )
103+ val browserslistFile = File (projectPath) / BrowsersListRc
104+ browserslistFile.delete(swallowIOExceptions = true )
105+ browserslistFile.createFile().deleteOnExit(swallowIOExceptions = true )
106+ browserslistFile.writeText(" last 2 years" )
107+ }
108+
109+ private def createCustomVueConfigFile (): Unit = {
110+ val vueConfigJsFile = File (projectPath) / VueConfigJs
111+ vueConfigJsFile.delete(swallowIOExceptions = true )
112+ vueConfigJsFile.createFile().deleteOnExit(swallowIOExceptions = true )
113+ if (vueVersion(config) <= 2 ) {
114+ vueConfigJsFile.writeText(Vue2Config )
115+ } else {
116+ vueConfigJsFile.writeText(Vue3Config )
75117 }
76- val customBrowserslistFile = File
77- .newTemporaryFile(" .browserslistrc" , parent = Some (projectPath))
78- .deleteOnExit(swallowIOExceptions = true )
79- customBrowserslistFile.writeText(" last 2 years" )
80118 }
81119
82120 override protected def transpile (tmpTranspileDir : Path ): Boolean = {
83121 if (installVuePlugins()) {
84122 createCustomBrowserslistFile()
85- val command = s " ${ExternalCommand .toOSCommand(vue)} build --dest ' $tmpTranspileDir' --mode development --no-clean "
123+ createCustomVueConfigFile()
124+ val command =
125+ s " ${ExternalCommand .toOSCommand(vue)} build --dest ' $tmpTranspileDir' --mode development --no-clean --modern "
86126 logger.debug(s " \t + Vue.js transpiling $projectPath to ' $tmpTranspileDir' " )
87127 ExternalCommand .run(command, projectPath.toString, extraEnv = VUE_NODE_OPTIONS ) match {
88128 case Success (_) => logger.debug(" \t + Vue.js transpiling finished" )
0 commit comments