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

org.jetbrains.kotlin.ir.backend.js.export.ExportModelToTsDeclarations.kt Maven / Gradle / Ivy

There is a newer version: 2.0.0
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.ir.backend.js.export

import org.jetbrains.kotlin.ir.backend.js.utils.sanitizeName
import org.jetbrains.kotlin.serialization.js.ModuleKind

// TODO: Support module kinds other than plain

fun ExportedModule.toTypeScript(): String {
    val indent = if (moduleKind == ModuleKind.PLAIN) "    " else ""
    val types = "${indent}type Nullable = T | null | undefined\n"

    val declarationsDts =
        types + declarations.joinToString("\n") {
            it.toTypeScript(
                indent = indent,
                prefix = if (moduleKind == ModuleKind.PLAIN) "" else "export "
            )
        }

    val namespaceName = sanitizeName(name)

    return when (moduleKind) {
        ModuleKind.PLAIN -> "declare namespace $namespaceName {\n$declarationsDts\n}\n"
        ModuleKind.AMD, ModuleKind.COMMON_JS -> declarationsDts
        ModuleKind.UMD -> "$declarationsDts\nexport as namespace $namespaceName;"
    }
}

fun List.toTypeScript(indent: String): String =
    joinToString("") { it.toTypeScript(indent) + "\n" }

fun ExportedDeclaration.toTypeScript(indent: String, prefix: String = ""): String = indent + when (this) {
    is ErrorDeclaration -> "/* ErrorDeclaration: $message */"

    is ExportedNamespace ->
        "${prefix}namespace $name {\n" + declarations.toTypeScript("$indent    ") + "$indent}"

    is ExportedFunction -> {
        val keyword: String = when {
            isMember -> when {
                isStatic -> "static "
                isAbstract -> "abstract "
                else -> ""
            }
            else -> "function "
        }

        val renderedParameters = parameters.joinToString(", ") { it.toTypeScript(indent) }

        val renderedTypeParameters =
            if (typeParameters.isNotEmpty())
                "<" + typeParameters.joinToString(", ") + ">"
            else
                ""

        val renderedReturnType = returnType.toTypeScript(indent)

        "${prefix}$keyword$name$renderedTypeParameters($renderedParameters): $renderedReturnType;"
    }
    is ExportedConstructor ->
        "constructor(${parameters.joinToString(", ") { it.toTypeScript(indent) }});"

    is ExportedProperty -> {
        val keyword = when {
            isMember -> (if (isAbstract) "abstract " else "") + (if (!mutable) "readonly " else "")
            else -> if (mutable) "let " else "const "
        }
        prefix + keyword + name + ": " + type.toTypeScript(indent) + ";"
    }

    is ExportedClass -> {
        val keyword = if (isInterface) "interface" else "class"
        val superInterfacesKeyword = if (isInterface) "extends" else "implements"

        val superClassClause = superClass?.let { " extends ${it.toTypeScript(indent)}" } ?: ""
        val superInterfacesClause = if (superInterfaces.isNotEmpty()) {
            " $superInterfacesKeyword " + superInterfaces.joinToString(", ") { it.toTypeScript(indent) }
        } else ""

        val membersString = members.joinToString("") { it.toTypeScript("$indent    ") + "\n" }

        // If there are no exported constructors, add a private constructor to disable default one
        val privateCtorString =
            if (!isInterface && !isAbstract && members.none { it is ExportedConstructor })
                "$indent    private constructor();\n"
            else
                ""

        val renderedTypeParameters =
            if (typeParameters.isNotEmpty())
                "<" + typeParameters.joinToString(", ") + ">"
            else
                ""

        val modifiers = if (isAbstract && !isInterface) "abstract " else ""

        val bodyString = privateCtorString + membersString + indent

        val klassExport = "$prefix$modifiers$keyword $name$renderedTypeParameters$superClassClause$superInterfacesClause {\n$bodyString}"
        val staticsExport = if (nestedClasses.isNotEmpty()) "\n" + ExportedNamespace(name, nestedClasses).toTypeScript(indent, prefix) else ""
        klassExport + staticsExport
    }
}

fun ExportedParameter.toTypeScript(indent: String): String =
    "$name: ${type.toTypeScript(indent)}"

fun ExportedType.toTypeScript(indent: String): String = when (this) {
    is ExportedType.Primitive -> typescript
    is ExportedType.Array -> "Array<${elementType.toTypeScript(indent)}>"
    is ExportedType.Function -> "(" + parameterTypes
        .withIndex()
        .joinToString(", ") { (index, type) ->
            "p$index: ${type.toTypeScript(indent)}"
        } + ") => " + returnType.toTypeScript(indent)

    is ExportedType.ClassType ->
        name + if (arguments.isNotEmpty()) "<${arguments.joinToString(", ") { it.toTypeScript(indent) }}>" else ""
    is ExportedType.TypeOf ->
        "typeof $name"

    is ExportedType.ErrorType -> "any /*$comment*/"
    is ExportedType.TypeParameter -> name
    is ExportedType.Nullable -> "Nullable<" + baseType.toTypeScript(indent) + ">"
    is ExportedType.InlineInterfaceType -> {
        members.joinToString(prefix = "{\n", postfix = "$indent}", separator = "") { it.toTypeScript("$indent    ") + "\n" }
    }
    is ExportedType.IntersectionType -> {
        lhs.toTypeScript(indent) + " & " + rhs.toTypeScript(indent)
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy