Wizard: add support of JS singleplatform projects

This commit is contained in:
Ilya Kirillov
2020-01-21 18:05:15 +03:00
parent b9226ce54f
commit dc26138da3
18 changed files with 121 additions and 30 deletions
@@ -19,6 +19,7 @@ import javax.swing.Icon
class CreateModuleOrTargetPopup private constructor( class CreateModuleOrTargetPopup private constructor(
private val target: Module?, private val target: Module?,
private val allowMultiplatform: Boolean, private val allowMultiplatform: Boolean,
private val allowSinglepaltformJs: Boolean,
private val allowAndroid: Boolean, private val allowAndroid: Boolean,
private val allowIos: Boolean, private val allowIos: Boolean,
private val createTarget: (TargetConfigurator) -> Unit, private val createTarget: (TargetConfigurator) -> Unit,
@@ -42,6 +43,7 @@ class CreateModuleOrTargetPopup private constructor(
if (allowMultiplatform) +MppModuleConfigurator if (allowMultiplatform) +MppModuleConfigurator
+JvmSinglePlatformModuleConfigurator +JvmSinglePlatformModuleConfigurator
if (allowAndroid) +AndroidSinglePlatformModuleConfigurator if (allowAndroid) +AndroidSinglePlatformModuleConfigurator
if (allowSinglepaltformJs) +JsSingleplatformModuleConfigurator
//todo ios support //todo ios support
//if (allowIos) +IOSSinglePlatformModuleConfigurator //if (allowIos) +IOSSinglePlatformModuleConfigurator
@@ -101,6 +103,7 @@ class CreateModuleOrTargetPopup private constructor(
fun create( fun create(
target: Module?, target: Module?,
allowMultiplatform: Boolean, allowMultiplatform: Boolean,
allowSinglepaltformJs: Boolean,
allowAndroid: Boolean, allowAndroid: Boolean,
allowIos: Boolean, allowIos: Boolean,
createTarget: (TargetConfigurator) -> Unit, createTarget: (TargetConfigurator) -> Unit,
@@ -108,6 +111,7 @@ class CreateModuleOrTargetPopup private constructor(
) = CreateModuleOrTargetPopup( ) = CreateModuleOrTargetPopup(
target = target, target = target,
allowMultiplatform = allowMultiplatform, allowMultiplatform = allowMultiplatform,
allowSinglepaltformJs = allowSinglepaltformJs,
allowAndroid = allowAndroid, allowAndroid = allowAndroid,
allowIos = allowIos, allowIos = allowIos,
createTarget = createTarget, createTarget = createTarget,
@@ -28,6 +28,7 @@ class ModulesEditorComponent(
moduleCreator.create( moduleCreator.create(
target = null, // The empty tree case target = null, // The empty tree case
allowMultiplatform = isMppProject, allowMultiplatform = isMppProject,
allowSinglepaltformJs = isMppProject,
allowAndroid = isMppProject, allowAndroid = isMppProject,
allowIos = isMppProject, allowIos = isMppProject,
allModules = value ?: emptyList(), allModules = value ?: emptyList(),
@@ -4,9 +4,7 @@ import com.intellij.icons.AllIcons
import com.intellij.openapi.actionSystem.ActionToolbarPosition import com.intellij.openapi.actionSystem.ActionToolbarPosition
import com.intellij.openapi.ui.Messages import com.intellij.openapi.ui.Messages
import com.intellij.ui.ToolbarDecorator import com.intellij.ui.ToolbarDecorator
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.AndroidSinglePlatformModuleConfigurator import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.*
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.IOSSinglePlatformModuleConfigurator
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.MppModuleConfigurator
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.withAllSubModules import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.withAllSubModules
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.* import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.*
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.createPanelWithPopupHandler import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.createPanelWithPopupHandler
@@ -31,6 +29,9 @@ class ModulesEditorToolbarDecorator(
allowMultiplatform = isMultiplatformProject() allowMultiplatform = isMultiplatformProject()
&& isRootModule && isRootModule
&& allModules.none { it.configurator == MppModuleConfigurator }, && allModules.none { it.configurator == MppModuleConfigurator },
allowSinglepaltformJs = isMultiplatformProject()
&& isRootModule
&& allModules.none { it.configurator == JsSingleplatformModuleConfigurator },
allowAndroid = isRootModule allowAndroid = isRootModule
&& isMultiplatformProject() && isMultiplatformProject()
&& allModules.none { it.configurator == AndroidSinglePlatformModuleConfigurator }, && allModules.none { it.configurator == AndroidSinglePlatformModuleConfigurator },
@@ -52,7 +53,8 @@ class ModulesEditorToolbarDecorator(
} }
text = "Add" + when (tree.selectedSettingItem?.safeAs<Module>()?.kind) { text = "Add" + when (tree.selectedSettingItem?.safeAs<Module>()?.kind) {
ModuleKind.multiplatform -> " Target" ModuleKind.multiplatform -> " Target"
ModuleKind.singleplatform -> " Module" ModuleKind.singleplatformJvm -> " Module"
ModuleKind.singleplatformJs -> " JS Module"
ModuleKind.target -> "" ModuleKind.target -> ""
null -> "" null -> ""
} }
@@ -105,6 +107,7 @@ class ModulesEditorToolbarDecorator(
private val Module.kindText private val Module.kindText
get() = when (kind) { get() = when (kind) {
ModuleKind.multiplatform -> "Module" ModuleKind.multiplatform -> "Module"
ModuleKind.singleplatform -> "Module" ModuleKind.singleplatformJvm -> "Module"
ModuleKind.singleplatformJs -> "Module"
ModuleKind.target -> "Target" ModuleKind.target -> "Target"
} }
@@ -36,6 +36,7 @@ class NewModuleCreator {
fun create( fun create(
target: Module?, target: Module?,
allowMultiplatform: Boolean, allowMultiplatform: Boolean,
allowSinglepaltformJs: Boolean,
allowAndroid: Boolean, allowAndroid: Boolean,
allowIos: Boolean, allowIos: Boolean,
allModules: List<Module>, allModules: List<Module>,
@@ -43,6 +44,7 @@ class NewModuleCreator {
) = CreateModuleOrTargetPopup.create( ) = CreateModuleOrTargetPopup.create(
target = target, target = target,
allowMultiplatform = allowMultiplatform, allowMultiplatform = allowMultiplatform,
allowSinglepaltformJs = allowSinglepaltformJs,
allowAndroid = allowAndroid, allowAndroid = allowAndroid,
allowIos = allowIos, allowIos = allowIos,
createTarget = { targetConfigurator -> createTarget = { targetConfigurator ->
@@ -22,7 +22,7 @@ class TargetsModel(
DefaultMutableTreeNode(moduleToAdd).apply { DefaultMutableTreeNode(moduleToAdd).apply {
val userObject = parentToAdd.userObject val userObject = parentToAdd.userObject
when { when {
userObject is Module && userObject.kind == ModuleKind.singleplatform -> { userObject is Module && userObject.kind == ModuleKind.singleplatformJvm -> {
val indexOfLastModule = parentToAdd.children() val indexOfLastModule = parentToAdd.children()
.toList() .toList()
.indexOfLast { .indexOfLast {
@@ -91,7 +91,8 @@ val Module.icon: Icon
get() = when (kind) { get() = when (kind) {
ModuleKind.target -> configurator.moduleType.icon ModuleKind.target -> configurator.moduleType.icon
ModuleKind.multiplatform -> AllIcons.Nodes.Module ModuleKind.multiplatform -> AllIcons.Nodes.Module
ModuleKind.singleplatform -> AllIcons.Nodes.Module ModuleKind.singleplatformJs -> KotlinIcons.JS
ModuleKind.singleplatformJvm -> AllIcons.Nodes.Module
} }
@@ -0,0 +1,12 @@
import kotlin.browser.document
import kotlin.test.Test
import kotlin.test.assertEquals
class TestClient {
@Test
fun testSayHello() {
val container = document.createElement("div")
container.sayHello()
assertEquals("Hello from JS", container.textContent)
}
}
@@ -1,14 +1,17 @@
import kotlinx.html.div import kotlinx.html.div
import kotlinx.html.dom.append import kotlinx.html.dom.append
import org.w3c.dom.Node
import kotlin.browser.document import kotlin.browser.document
import kotlin.browser.window import kotlin.browser.window
fun main() { fun main() {
window.onload = { window.onload = { document.body?.sayHello() }
document.body?.append { }
div {
+"Hello from JS" fun Node.sayHello() {
} append {
div {
+"Hello from JS"
} }
} }
} }
@@ -81,6 +81,6 @@ data class KotlinBuildSystemPluginIR(
@Suppress("EnumEntryName", "unused", "SpellCheckingInspection") @Suppress("EnumEntryName", "unused", "SpellCheckingInspection")
enum class Type { enum class Type {
jvm, multiplatform, android jvm, multiplatform, android, js
} }
} }
@@ -15,7 +15,7 @@ interface GradleIR : BuildSystemIR {
data class RawGradleIR( data class RawGradleIR(
val renderer: GradlePrinter.() -> Unit val renderer: GradlePrinter.() -> Unit
) : GradleIR { ) : GradleIR, FreeIR {
override fun GradlePrinter.renderGradle() = renderer() override fun GradlePrinter.renderGradle() = renderer()
} }
@@ -0,0 +1,42 @@
/*
* Copyright 2010-2020 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.tools.projectWizard.moduleConfigurators
import org.jetbrains.kotlin.tools.projectWizard.core.buildList
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.BuildSystemIR
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.KotlinBuildSystemPluginIR
import org.jetbrains.kotlin.tools.projectWizard.ir.buildsystem.gradle.RawGradleIR
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModuleConfigurationData
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModuleType
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Module
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.ModuleKind
abstract class JSConfigurator : ModuleConfiguratorWithTests() {
override val moduleType: ModuleType get() = ModuleType.js
override fun defaultTestFramework(): KotlinTestFramework = KotlinTestFramework.JS
}
object JsSingleplatformModuleConfigurator : JSConfigurator() {
override val moduleKind = ModuleKind.singleplatformJs
override val suggestedModuleName = "js"
override val id = "jsSinglepaltform"
override val text = "JS for Browser"
override val canContainSubModules = false
override fun createKotlinPluginIR(configurationData: ModuleConfigurationData, module: Module): KotlinBuildSystemPluginIR? =
KotlinBuildSystemPluginIR(
KotlinBuildSystemPluginIR.Type.js,
version = configurationData.kotlinVersion
)
override fun createBuildFileIRs(configurationData: ModuleConfigurationData, module: Module): List<BuildSystemIR> = buildList {
+RawGradleIR {
+"kotlin.target.browser { }"
}
}
}
@@ -51,11 +51,7 @@ private fun Module.createTargetAccessIr(moduleSubType: ModuleSubType) =
) )
abstract class JsTargetConfigurator : TargetConfiguratorWithTests(), SingleCoexistenceTargetConfigurator { abstract class JsTargetConfigurator : JSConfigurator(), TargetConfigurator, SingleCoexistenceTargetConfigurator
override val moduleType: ModuleType get() = ModuleType.js
override fun defaultTestFramework(): KotlinTestFramework = KotlinTestFramework.JS
}
object JsBrowserTargetConfigurator : JsTargetConfigurator() { object JsBrowserTargetConfigurator : JsTargetConfigurator() {
override val id = "jsBrowser" override val id = "jsBrowser"
@@ -27,7 +27,7 @@ object MppModuleConfigurator : ModuleConfigurator {
interface SinglePlatformModuleConfigurator : ModuleConfigurator { interface SinglePlatformModuleConfigurator : ModuleConfigurator {
override val moduleKind get() = ModuleKind.singleplatform override val moduleKind get() = ModuleKind.singleplatformJvm
} }
@@ -129,7 +129,7 @@ enum class ProjectKind(override val text: String) : DisplayableSettingItem {
fun List<Module>.withAllSubModules(includeSourcesets: Boolean = false): List<Module> = buildList { fun List<Module>.withAllSubModules(includeSourcesets: Boolean = false): List<Module> = buildList {
fun handleModule(module: Module) { fun handleModule(module: Module) {
+module +module
if (module.kind == ModuleKind.singleplatform if (module.kind == ModuleKind.singleplatformJvm
|| includeSourcesets && module.kind == ModuleKind.multiplatform || includeSourcesets && module.kind == ModuleKind.multiplatform
) { ) {
module.subModules.forEach(::handleModule) module.subModules.forEach(::handleModule)
@@ -87,7 +87,7 @@ class ModulesToIRsConverter(
state: ModulesToIrsState state: ModulesToIrsState
): TaskResult<List<BuildFileIR>> = when (module.kind) { ): TaskResult<List<BuildFileIR>> = when (module.kind) {
ModuleKind.multiplatform -> createMultiplatformModule(module, state) ModuleKind.multiplatform -> createMultiplatformModule(module, state)
ModuleKind.singleplatform -> createSinglePlatformModule(module, state) ModuleKind.singleplatformJvm, ModuleKind.singleplatformJs -> createSinglePlatformModule(module, state)
else -> Success(emptyList()) else -> Success(emptyList())
} }
@@ -4,6 +4,7 @@ import org.intellij.lang.annotations.Language
import org.jetbrains.kotlin.tools.projectWizard.core.buildList import org.jetbrains.kotlin.tools.projectWizard.core.buildList
import org.jetbrains.kotlin.tools.projectWizard.core.entity.* import org.jetbrains.kotlin.tools.projectWizard.core.entity.*
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.AndroidSinglePlatformModuleConfigurator import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.AndroidSinglePlatformModuleConfigurator
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.JsSingleplatformModuleConfigurator
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.MppModuleConfigurator import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.MppModuleConfigurator
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.defaultTarget import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.defaultTarget
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.KotlinPlugin import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.KotlinPlugin
@@ -54,7 +55,8 @@ sealed class ProjectTemplate : DisplayableSettingItem {
JvmServerJsClient, JvmServerJsClient,
MultiplatformLibrary, MultiplatformLibrary,
AndroidApplication, AndroidApplication,
NativeConsoleApplication NativeConsoleApplication,
JsBrowserApplication
) )
} }
} }
@@ -206,7 +208,7 @@ object AndroidApplication : ProjectTemplate() {
KotlinPlugin::modules withValue listOf( KotlinPlugin::modules withValue listOf(
Module( Module(
"app", "app",
ModuleKind.singleplatform, ModuleKind.singleplatformJvm,
AndroidSinglePlatformModuleConfigurator, AndroidSinglePlatformModuleConfigurator,
template = null, template = null,
sourcesets = SourcesetType.ALL.map { type -> sourcesets = SourcesetType.ALL.map { type ->
@@ -241,4 +243,27 @@ object NativeConsoleApplication : ProjectTemplate() {
) )
) )
) )
}
object JsBrowserApplication : ProjectTemplate() {
override val title = "Kotlin/JS Frontend Application"
override val htmlDescription = title
override val suggestedProjectName = "myKotlinJsApplication"
override val projectKind = ProjectKind.Multiplatform
override val setsPluginSettings: List<SettingWithValue<*, *>>
get() = listOf(
KotlinPlugin::modules withValue listOf(
Module(
"frontend",
ModuleKind.singleplatformJs,
JsSingleplatformModuleConfigurator,
template = SimpleJsClientTemplate(),
sourcesets = SourcesetType.ALL.map { type ->
Sourceset(type, ModuleType.jvm, dependencies = emptyList())
},
subModules = emptyList()
)
)
)
} }
@@ -13,7 +13,8 @@ import org.jetbrains.kotlin.tools.projectWizard.templates.Template
enum class ModuleKind { enum class ModuleKind {
multiplatform, multiplatform,
target, target,
singleplatform singleplatformJvm,
singleplatformJs,
} }
// TODO separate to classes // TODO separate to classes
@@ -150,7 +151,7 @@ fun MultiplatformModule(name: String, targets: List<Module> = emptyList()) =
fun SingleplatformModule(name: String, sourcesets: List<Sourceset>) = fun SingleplatformModule(name: String, sourcesets: List<Sourceset>) =
Module( Module(
name, name,
ModuleKind.singleplatform, ModuleKind.singleplatformJvm,
JvmSinglePlatformModuleConfigurator, JvmSinglePlatformModuleConfigurator,
null, null,
sourcesets, sourcesets,
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.tools.projectWizard.transformers.interceptors.Templa
import org.jetbrains.kotlin.tools.projectWizard.transformers.interceptors.interceptTemplate import org.jetbrains.kotlin.tools.projectWizard.transformers.interceptors.interceptTemplate
class SimpleJsClientTemplate : Template() { class SimpleJsClientTemplate : Template() {
override val title: String = "Simple JS client" override val title: String = "JS client"
override val htmlDescription: String = title override val htmlDescription: String = title
override val moduleTypes: Set<ModuleType> = setOf(ModuleType.js) override val moduleTypes: Set<ModuleType> = setOf(ModuleType.js)
override val id: String = "simpleJsClient" override val id: String = "simpleJsClient"
@@ -41,9 +41,10 @@ class SimpleJsClientTemplate : Template() {
) )
} }
override fun TaskRunningContext.getFileTemplates(module: ModuleIR): List<FileTemplateDescriptorWithPath> = listOf( override fun TaskRunningContext.getFileTemplates(module: ModuleIR): List<FileTemplateDescriptorWithPath> = buildList {
FileTemplateDescriptor("$id/client.kt.vm", "client.kt".asPath()) asSrcOf SourcesetType.main +(FileTemplateDescriptor("$id/client.kt.vm", "client.kt".asPath()) asSrcOf SourcesetType.main)
) +(FileTemplateDescriptor("$id/TestClient.kt.vm", "TestClient.kt".asPath()) asSrcOf SourcesetType.test)
}
override fun createInterceptors(module: ModuleIR): List<TemplateInterceptor> = buildList { override fun createInterceptors(module: ModuleIR): List<TemplateInterceptor> = buildList {
+interceptTemplate(KtorServerTemplate()) { +interceptTemplate(KtorServerTemplate()) {