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

org.jetbrains.kotlin.gradle.targets.js.npm.resolver.KotlinProjectNpmResolver.kt Maven / Gradle / Ivy

There is a newer version: 2.0.20-RC
Show newest version
/*
 * 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.resolver

import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinSingleTargetExtension
import org.jetbrains.kotlin.gradle.dsl.kotlinExtensionOrNull
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
import org.jetbrains.kotlin.gradle.targets.js.RequiredKotlinJsDependency
import org.jetbrains.kotlin.gradle.targets.js.npm.RequiresNpmDependencies
import org.jetbrains.kotlin.gradle.targets.js.npm.resolved.KotlinProjectNpmResolution

/**
 * See [KotlinNpmResolutionManager] for details about resolution process.
 */
internal class KotlinProjectNpmResolver(
    val project: Project,
    val resolver: KotlinRootNpmResolver
) {
    override fun toString(): String = "ProjectNpmResolver($project)"

    private val byCompilation = mutableMapOf()

    operator fun get(compilation: KotlinJsCompilation): KotlinCompilationNpmResolver {
        check(compilation.target.project == project)
        return byCompilation[compilation] ?: error("$compilation was not registered in $this")
    }

    private var closed = false

    val compilationResolvers: Collection
        get() = byCompilation.values

    val taskRequirements by lazy { TasksRequirements(this) }

    init {
        addContainerListeners()
    }

    private fun addContainerListeners() {
        val kotlin = project.kotlinExtensionOrNull
            ?: error("NpmResolverPlugin should be applied after kotlin plugin")

        when (kotlin) {
            is KotlinSingleTargetExtension -> addTargetListeners(kotlin.target)
            is KotlinMultiplatformExtension -> kotlin.targets.all {
                addTargetListeners(it)
            }
            else -> error("Unsupported kotlin model: $kotlin")
        }
    }

    private fun addTargetListeners(target: KotlinTarget) {
        check(!closed) { resolver.alreadyResolvedMessage("add target $target") }

        if (target.platformType == KotlinPlatformType.js) {
            target.compilations.all { compilation ->
                if (compilation is KotlinJsCompilation) {
                    // compilation may be KotlinWithJavaTarget for old Kotlin2JsPlugin
                    addCompilation(compilation)
                }
            }
        }
    }

    @Synchronized
    private fun addCompilation(compilation: KotlinJsCompilation) {
        check(!closed) { resolver.alreadyResolvedMessage("add compilation $compilation") }

        byCompilation[compilation] = KotlinCompilationNpmResolver(this, compilation)
    }

    fun close(): KotlinProjectNpmResolution {
        check(!closed)
        closed = true

        return KotlinProjectNpmResolution(
            project,
            byCompilation.values.mapNotNull { it.close() },
            taskRequirements.byTask
        )
    }

    class TasksRequirements(val projectNpmResolver: KotlinProjectNpmResolver) {
        val byTask = mutableMapOf>()
        val byCompilation = mutableMapOf>()

        fun getTaskRequirements(compilation: KotlinJsCompilation): Collection =
            byCompilation[compilation] ?: listOf()

        val hasNodeModulesDependentTasks: Boolean
            get() = _hasNodeModulesDependentTasks

        @Volatile
        var _hasNodeModulesDependentTasks = false
            private set

        init {
            projectNpmResolver.project.tasks.forEach { task ->
                if (task.enabled && task is RequiresNpmDependencies) {
                    addTaskRequirements(task)
                    task.dependsOn(projectNpmResolver[task.compilation].packageJsonTaskHolder)
                    task.dependsOn(projectNpmResolver.resolver.nodeJs.npmInstallTask)
                }
            }
        }

        private fun addTaskRequirements(task: RequiresNpmDependencies) {
            if (!_hasNodeModulesDependentTasks && task.nodeModulesRequired) {
                _hasNodeModulesDependentTasks = true
            }

            val requirements = task.requiredNpmDependencies.toList()

            byTask[task] = requirements

            byCompilation
                .getOrPut(task.compilation) { mutableListOf() }
                .add(task)
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy