From b9f69ffe79e51ae5e6c5449f853f656dd1f85568 Mon Sep 17 00:00:00 2001 From: Sergey Rostov Date: Tue, 14 May 2019 13:14:30 +0300 Subject: [PATCH] Gradle, js: extract NpmProjectModules to separate file #KT-30530 --- .../gradle/targets/js/npm/NpmProject.kt | 72 +++------------ .../targets/js/npm/NpmProjectModules.kt | 87 +++++++++++++++++++ 2 files changed, 100 insertions(+), 59 deletions(-) create mode 100644 libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProjectModules.kt diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProject.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProject.kt index 3ce5d0bb755..1617fa9f12a 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProject.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProject.kt @@ -5,8 +5,6 @@ package org.jetbrains.kotlin.gradle.targets.js.npm -import com.google.gson.Gson -import com.google.gson.JsonObject import org.gradle.api.Project import org.gradle.process.ExecSpec import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsPlugin @@ -28,14 +26,13 @@ open class NpmProject( open val compileOutputCopyDest: File? get() = nodeModulesDir - fun useTool(exec: ExecSpec, tool: String, vararg args: String) { - NpmResolver.resolve(project) - - exec.workingDir = nodeWorkDir - exec.executable = project.nodeJs.root.environment.nodeExecutable - exec.args = listOf(require(tool)) + args + private val modules = object : NpmProjectModules(nodeWorkDir, nodeModulesDir) { + override val parent get() = if (searchInParents) parentModules else null } + private val parentModules: NpmProjectModules? + get() = project.parent?.npmProject?.modules + val hoistGradleNodeModules: Boolean get() = project.nodeJs.root.packageManager.shouldHoistGradleNodeModules(project) @@ -48,68 +45,25 @@ open class NpmProject( return compileOutputCopyDest?.resolve(compilationTask.outputFile.name) ?: compilationTask.outputFile } + fun useTool(exec: ExecSpec, tool: String, vararg args: String) { + exec.workingDir = nodeWorkDir + exec.executable = project.nodeJs.root.environment.nodeExecutable + exec.args = listOf(require(tool)) + args + } + /** * Require [request] nodejs module and return canonical path to it's main js file. */ fun require(request: String): String { NpmResolver.requireResolved(project) - return resolve(request)?.canonicalPath ?: error("Cannot find node module \"$request\" in \"$this\"") + return modules.require(request) } /** * Find node module according to https://nodejs.org/api/modules.html#modules_all_together, * with exception that instead of traversing parent folders, we are traversing parent projects */ - internal fun resolve(name: String, context: File = nodeWorkDir): File? = - if (name.startsWith("/")) resolve(name.removePrefix("/"), File("/")) - else resolveAsRelative("./", name, context) - ?: resolveAsRelative("/", name, context) - ?: resolveAsRelative("../", name, context) - ?: resolveInNodeModulesDir(name, nodeModulesDir) - ?: if (searchInParents) project.parent?.let { NpmProject[it].resolve(name) } else null - - private fun resolveAsRelative(prefix: String, name: String, context: File): File? { - if (!name.startsWith(prefix)) return null - - val relative = context.resolve(name.removePrefix(prefix)) - return resolveAsFile(relative) - ?: resolveAsDirectory(relative) - } - - private fun resolveInNodeModulesDir(name: String, nodeModulesDir: File): File? { - return resolveAsFile(nodeModulesDir.resolve(name)) - ?: resolveAsDirectory(nodeModulesDir.resolve(name)) - } - - private fun resolveAsDirectory(dir: File): File? { - val packageJsonFile = dir.resolve("package.json") - val main: String? = if (packageJsonFile.isFile) { - val packageJson = packageJsonFile.reader().use { - Gson().fromJson(it, JsonObject::class.java) - } - - packageJson["main"] as? String? - ?: packageJson["module"] as? String? - ?: packageJson["browser"] as? String? - } else null - - return if (main != null) { - val mainFile = dir.resolve(main) - resolveAsFile(mainFile) - ?: resolveIndex(mainFile) - } else resolveIndex(dir) - } - - private fun resolveIndex(dir: File): File? = resolveAsFile(dir.resolve("index")) - - private fun resolveAsFile(file: File): File? { - if (file.isFile) return file - - val js = File(file.path + ".js") - if (js.isFile) return js - - return null - } + internal fun resolve(name: String): File? = modules.resolve(name) override fun toString() = "NpmProject($nodeWorkDir)" diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProjectModules.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProjectModules.kt new file mode 100644 index 00000000000..dfb37969dcc --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProjectModules.kt @@ -0,0 +1,87 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.targets.js.npm + +import com.google.gson.Gson +import com.google.gson.JsonObject +import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject.Companion.NODE_MODULES +import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject.Companion.PACKAGE_JSON +import java.io.File + +internal open class NpmProjectModules( + val dir: File, + val nodeModulesDir: File = dir.resolve(NODE_MODULES) +) { + /** + * Require [request] nodejs module and return canonical path to it's main js file. + */ + fun require(request: String): String { + return resolve(request)?.canonicalPath ?: error("Cannot find node module \"$request\" in \"$this\"") + } + + open val parent: NpmProjectModules? + get() = null + + /** + * Find node module according to https://nodejs.org/api/modules.html#modules_all_together, + * with exception that instead of traversing parent folders, we are traversing parent projects + */ + internal fun resolve(name: String, context: File = dir): File? = + if (name.startsWith("/")) resolve(name.removePrefix("/"), File("/")) + else resolveAsRelative("./", name, context) + ?: resolveAsRelative("/", name, context) + ?: resolveAsRelative("../", name, context) + ?: resolveInNodeModulesDir(name, nodeModulesDir) + ?: parent?.resolve(name) + + private fun resolveAsRelative(prefix: String, name: String, context: File): File? { + if (!name.startsWith(prefix)) return null + + val relative = context.resolve(name.removePrefix(prefix)) + return resolveAsFile(relative) + ?: resolveAsDirectory(relative) + } + + private fun resolveInNodeModulesDir(name: String, nodeModulesDir: File): File? { + return resolveAsFile(nodeModulesDir.resolve(name)) + ?: resolveAsDirectory(nodeModulesDir.resolve(name)) + } + + private fun resolveAsDirectory(dir: File): File? { + val packageJsonFile = dir.resolve(PACKAGE_JSON) + val main: String? = if (packageJsonFile.isFile) { + val packageJson = packageJsonFile.reader().use { + Gson().fromJson(it, JsonObject::class.java) + } + + packageJson["main"] as? String? + ?: packageJson["module"] as? String? + ?: packageJson["browser"] as? String? + } else null + + return if (main != null) { + val mainFile = dir.resolve(main) + resolveAsFile(mainFile) + ?: resolveIndex(mainFile) + } else resolveIndex(dir) + } + + private fun resolveIndex(dir: File): File? = resolveAsFile(dir.resolve(INDEX_FILE_NAME)) + + private fun resolveAsFile(file: File): File? { + if (file.isFile) return file + + val js = File(file.path + JS_SUFFIX) + if (js.isFile) return js + + return null + } + + companion object { + const val JS_SUFFIX = ".js" + const val INDEX_FILE_NAME = "index" + } +} \ No newline at end of file