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

kotlin.script.experimental.jvm.impl.BridgeDependenciesResolver.kt Maven / Gradle / Ivy

There is a newer version: 2.1.0-RC2
Show newest version
/*
 * Copyright 2010-2018 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 kotlin.script.experimental.jvm.impl

import java.io.File
import kotlin.script.dependencies.Environment
import kotlin.script.dependencies.ScriptContents
import kotlin.script.experimental.api.*
import kotlin.script.experimental.dependencies.AsyncDependenciesResolver
import kotlin.script.experimental.dependencies.DependenciesResolver
import kotlin.script.experimental.dependencies.ScriptDependencies
import kotlin.script.experimental.dependencies.ScriptReport
import kotlin.script.experimental.host.FileScriptSource
import kotlin.script.experimental.host.toScriptSource
import kotlin.script.experimental.impl.internalScriptingRunSuspend
import kotlin.script.experimental.jvm.JvmDependency
import kotlin.script.experimental.jvm.compat.mapToLegacyScriptReportPosition
import kotlin.script.experimental.jvm.compat.mapToLegacyScriptReportSeverity

class BridgeDependenciesResolver(
    val scriptCompilationConfiguration: ScriptCompilationConfiguration,
    val onConfigurationUpdated: (SourceCode, ScriptCompilationConfiguration) -> Unit = { _, _ -> },
    val getScriptSource: (ScriptContents) -> SourceCode? = { null }
) : AsyncDependenciesResolver {

    override fun resolve(scriptContents: ScriptContents, environment: Environment): DependenciesResolver.ResolveResult =
        @Suppress("DEPRECATION_ERROR")
        internalScriptingRunSuspend {
            resolveAsync(scriptContents, environment)
        }

    override suspend fun resolveAsync(scriptContents: ScriptContents, environment: Environment): DependenciesResolver.ResolveResult {
        try {

            val diagnostics = arrayListOf()
            val processedScriptData = ScriptCollectedData(
                mapOf(
                    ScriptCollectedData.foundAnnotations to scriptContents.annotations
                )
            )

            val script = getScriptSource(scriptContents) ?: scriptContents.toScriptSource()

            val refineResults =
                scriptCompilationConfiguration.refineOnAnnotations(script, processedScriptData).onSuccess {
                    it.refineBeforeCompiling(script, processedScriptData)
                }

            val refinedConfiguration = when (refineResults) {
                is ResultWithDiagnostics.Failure ->
                    return DependenciesResolver.ResolveResult.Failure(refineResults.reports.mapScriptReportsToDiagnostics())
                is ResultWithDiagnostics.Success -> {
                    diagnostics.addAll(refineResults.reports.mapScriptReportsToDiagnostics())
                    refineResults.value
                }
            }

            if (refinedConfiguration != scriptCompilationConfiguration) {
                onConfigurationUpdated(script, refinedConfiguration)
            }

            val newClasspath = refinedConfiguration[ScriptCompilationConfiguration.dependencies]
                ?.flatMap { (it as JvmDependency).classpath } ?: emptyList()

            return DependenciesResolver.ResolveResult.Success(
                // TODO: consider returning only increment from the initial config
                refinedConfiguration.toDependencies(newClasspath),
                diagnostics
            )
        } catch (e: Throwable) {
            return DependenciesResolver.ResolveResult.Failure(
                ScriptReport(e.message ?: "unknown error $e")
            )
        }
    }
}

fun ScriptCompilationConfiguration.toDependencies(classpath: List): ScriptDependencies {
    val defaultImports = this[ScriptCompilationConfiguration.defaultImports]?.toList() ?: emptyList()

    return ScriptDependencies(
        classpath = classpath,
        sources = this[ScriptCompilationConfiguration.ide.dependenciesSources].toClassPathOrEmpty(),
        imports = defaultImports,
        scripts = this[ScriptCompilationConfiguration.importScripts].toFilesOrEmpty()
    )
}

internal fun List.mapScriptReportsToDiagnostics() =
    map { ScriptReport(it.message, mapToLegacyScriptReportSeverity(it.severity), mapToLegacyScriptReportPosition(it.location)) }

internal fun ScriptContents.toScriptSource(): SourceCode = when {
    file != null -> FileScriptSource(file!!, text?.toString())
    text != null -> text!!.toString().toScriptSource()
    else -> throw IllegalArgumentException("Unable to convert script contents $this into script source")
}

fun List?.toClassPathOrEmpty() = this?.flatMap { (it as? JvmDependency)?.classpath ?: emptyList() } ?: emptyList()

internal fun List?.toFilesOrEmpty() = this?.map {
    val externalSource = it as? ExternalSourceCode
    externalSource?.externalLocation?.toFileOrNull()
        ?: throw RuntimeException("Unsupported source in requireSources parameter - only local files are supported now (${externalSource?.externalLocation})")
} ?: emptyList()

fun ScriptCompilationConfiguration.refineWith(
    handler: RefineScriptCompilationConfigurationHandler?,
    processedScriptData: ScriptCollectedData,
    script: SourceCode
): ResultWithDiagnostics =
    if (handler == null) this.asSuccess()
    else handler(ScriptConfigurationRefinementContext(script, this, processedScriptData))




© 2015 - 2024 Weber Informatics LLC | Privacy Policy