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(
private val target: Module?,
private val allowMultiplatform: Boolean,
private val allowSinglepaltformJs: Boolean,
private val allowAndroid: Boolean,
private val allowIos: Boolean,
private val createTarget: (TargetConfigurator) -> Unit,
@@ -42,6 +43,7 @@ class CreateModuleOrTargetPopup private constructor(
if (allowMultiplatform) +MppModuleConfigurator
+JvmSinglePlatformModuleConfigurator
if (allowAndroid) +AndroidSinglePlatformModuleConfigurator
if (allowSinglepaltformJs) +JsSingleplatformModuleConfigurator
//todo ios support
//if (allowIos) +IOSSinglePlatformModuleConfigurator
@@ -101,6 +103,7 @@ class CreateModuleOrTargetPopup private constructor(
fun create(
target: Module?,
allowMultiplatform: Boolean,
allowSinglepaltformJs: Boolean,
allowAndroid: Boolean,
allowIos: Boolean,
createTarget: (TargetConfigurator) -> Unit,
@@ -108,6 +111,7 @@ class CreateModuleOrTargetPopup private constructor(
) = CreateModuleOrTargetPopup(
target = target,
allowMultiplatform = allowMultiplatform,
allowSinglepaltformJs = allowSinglepaltformJs,
allowAndroid = allowAndroid,
allowIos = allowIos,
createTarget = createTarget,
@@ -28,6 +28,7 @@ class ModulesEditorComponent(
moduleCreator.create(
target = null, // The empty tree case
allowMultiplatform = isMppProject,
allowSinglepaltformJs = isMppProject,
allowAndroid = isMppProject,
allowIos = isMppProject,
allModules = value ?: emptyList(),
@@ -4,9 +4,7 @@ import com.intellij.icons.AllIcons
import com.intellij.openapi.actionSystem.ActionToolbarPosition
import com.intellij.openapi.ui.Messages
import com.intellij.ui.ToolbarDecorator
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.AndroidSinglePlatformModuleConfigurator
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.IOSSinglePlatformModuleConfigurator
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.MppModuleConfigurator
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.*
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.withAllSubModules
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.*
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.createPanelWithPopupHandler
@@ -31,6 +29,9 @@ class ModulesEditorToolbarDecorator(
allowMultiplatform = isMultiplatformProject()
&& isRootModule
&& allModules.none { it.configurator == MppModuleConfigurator },
allowSinglepaltformJs = isMultiplatformProject()
&& isRootModule
&& allModules.none { it.configurator == JsSingleplatformModuleConfigurator },
allowAndroid = isRootModule
&& isMultiplatformProject()
&& allModules.none { it.configurator == AndroidSinglePlatformModuleConfigurator },
@@ -52,7 +53,8 @@ class ModulesEditorToolbarDecorator(
}
text = "Add" + when (tree.selectedSettingItem?.safeAs<Module>()?.kind) {
ModuleKind.multiplatform -> " Target"
ModuleKind.singleplatform -> " Module"
ModuleKind.singleplatformJvm -> " Module"
ModuleKind.singleplatformJs -> " JS Module"
ModuleKind.target -> ""
null -> ""
}
@@ -105,6 +107,7 @@ class ModulesEditorToolbarDecorator(
private val Module.kindText
get() = when (kind) {
ModuleKind.multiplatform -> "Module"
ModuleKind.singleplatform -> "Module"
ModuleKind.singleplatformJvm -> "Module"
ModuleKind.singleplatformJs -> "Module"
ModuleKind.target -> "Target"
}
@@ -36,6 +36,7 @@ class NewModuleCreator {
fun create(
target: Module?,
allowMultiplatform: Boolean,
allowSinglepaltformJs: Boolean,
allowAndroid: Boolean,
allowIos: Boolean,
allModules: List<Module>,
@@ -43,6 +44,7 @@ class NewModuleCreator {
) = CreateModuleOrTargetPopup.create(
target = target,
allowMultiplatform = allowMultiplatform,
allowSinglepaltformJs = allowSinglepaltformJs,
allowAndroid = allowAndroid,
allowIos = allowIos,
createTarget = { targetConfigurator ->
@@ -22,7 +22,7 @@ class TargetsModel(
DefaultMutableTreeNode(moduleToAdd).apply {
val userObject = parentToAdd.userObject
when {
userObject is Module && userObject.kind == ModuleKind.singleplatform -> {
userObject is Module && userObject.kind == ModuleKind.singleplatformJvm -> {
val indexOfLastModule = parentToAdd.children()
.toList()
.indexOfLast {
@@ -91,7 +91,8 @@ val Module.icon: Icon
get() = when (kind) {
ModuleKind.target -> configurator.moduleType.icon
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.dom.append
import org.w3c.dom.Node
import kotlin.browser.document
import kotlin.browser.window
fun main() {
window.onload = {
document.body?.append {
div {
+"Hello from JS"
}
window.onload = { document.body?.sayHello() }
}
fun Node.sayHello() {
append {
div {
+"Hello from JS"
}
}
}
@@ -81,6 +81,6 @@ data class KotlinBuildSystemPluginIR(
@Suppress("EnumEntryName", "unused", "SpellCheckingInspection")
enum class Type {
jvm, multiplatform, android
jvm, multiplatform, android, js
}
}
@@ -15,7 +15,7 @@ interface GradleIR : BuildSystemIR {
data class RawGradleIR(
val renderer: GradlePrinter.() -> Unit
) : GradleIR {
) : GradleIR, FreeIR {
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 {
override val moduleType: ModuleType get() = ModuleType.js
override fun defaultTestFramework(): KotlinTestFramework = KotlinTestFramework.JS
}
abstract class JsTargetConfigurator : JSConfigurator(), TargetConfigurator, SingleCoexistenceTargetConfigurator
object JsBrowserTargetConfigurator : JsTargetConfigurator() {
override val id = "jsBrowser"
@@ -27,7 +27,7 @@ object MppModuleConfigurator : 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 handleModule(module: Module) {
+module
if (module.kind == ModuleKind.singleplatform
if (module.kind == ModuleKind.singleplatformJvm
|| includeSourcesets && module.kind == ModuleKind.multiplatform
) {
module.subModules.forEach(::handleModule)
@@ -87,7 +87,7 @@ class ModulesToIRsConverter(
state: ModulesToIrsState
): TaskResult<List<BuildFileIR>> = when (module.kind) {
ModuleKind.multiplatform -> createMultiplatformModule(module, state)
ModuleKind.singleplatform -> createSinglePlatformModule(module, state)
ModuleKind.singleplatformJvm, ModuleKind.singleplatformJs -> createSinglePlatformModule(module, state)
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.entity.*
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.defaultTarget
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.KotlinPlugin
@@ -54,7 +55,8 @@ sealed class ProjectTemplate : DisplayableSettingItem {
JvmServerJsClient,
MultiplatformLibrary,
AndroidApplication,
NativeConsoleApplication
NativeConsoleApplication,
JsBrowserApplication
)
}
}
@@ -206,7 +208,7 @@ object AndroidApplication : ProjectTemplate() {
KotlinPlugin::modules withValue listOf(
Module(
"app",
ModuleKind.singleplatform,
ModuleKind.singleplatformJvm,
AndroidSinglePlatformModuleConfigurator,
template = null,
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 {
multiplatform,
target,
singleplatform
singleplatformJvm,
singleplatformJs,
}
// TODO separate to classes
@@ -150,7 +151,7 @@ fun MultiplatformModule(name: String, targets: List<Module> = emptyList()) =
fun SingleplatformModule(name: String, sourcesets: List<Sourceset>) =
Module(
name,
ModuleKind.singleplatform,
ModuleKind.singleplatformJvm,
JvmSinglePlatformModuleConfigurator,
null,
sourcesets,
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.tools.projectWizard.transformers.interceptors.Templa
import org.jetbrains.kotlin.tools.projectWizard.transformers.interceptors.interceptTemplate
class SimpleJsClientTemplate : Template() {
override val title: String = "Simple JS client"
override val title: String = "JS client"
override val htmlDescription: String = title
override val moduleTypes: Set<ModuleType> = setOf(ModuleType.js)
override val id: String = "simpleJsClient"
@@ -41,9 +41,10 @@ class SimpleJsClientTemplate : Template() {
)
}
override fun TaskRunningContext.getFileTemplates(module: ModuleIR): List<FileTemplateDescriptorWithPath> = listOf(
FileTemplateDescriptor("$id/client.kt.vm", "client.kt".asPath()) asSrcOf SourcesetType.main
)
override fun TaskRunningContext.getFileTemplates(module: ModuleIR): List<FileTemplateDescriptorWithPath> = buildList {
+(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 {
+interceptTemplate(KtorServerTemplate()) {