Skip to content

Commit e14d15f

Browse files
author
Oleksandr Dzhychko
committed
feat(model-client): add and publish a model client library for JavaScript
The model client in Kotlin is multiplatform, but not usable from JavaScript because it does not export the appropriate functionality for usage from JavaScript and needs to be used inside coroutines, which cannot be directly created in JavaScript.
1 parent fb182c3 commit e14d15f

File tree

6 files changed

+548
-0
lines changed

6 files changed

+548
-0
lines changed

gradle/libs.versions.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ modelix-mps-buildtools = { id = "org.modelix.mps.build-tools", version = "1.1.0"
1818
dokka = {id = "org.jetbrains.dokka", version = "1.9.0"}
1919
node = {id = "com.github.node-gradle.node", version = "7.0.1"}
2020
detekt = { id = "io.gitlab.arturbosch.detekt", version = "1.23.1" }
21+
npm-publish = { id = "dev.petuska.npm.publish", version = "3.4.1" }
2122

2223
[versions]
2324
kotlin = "1.9.10"
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright (c) 2023.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.modelix.kotlin.utils
18+
19+
/**
20+
* Marks an API as unstable.
21+
*
22+
* @param reason Describes why the feature is experimental.
23+
* @param intendedFinalization Describes when this API is intended to be finalized or removed.
24+
*/
25+
@RequiresOptIn(message = "This API is experimental. It may be changed in the future without notice.")
26+
@Retention(AnnotationRetention.BINARY)
27+
@Target(
28+
AnnotationTarget.CLASS,
29+
AnnotationTarget.FUNCTION,
30+
AnnotationTarget.PROPERTY,
31+
AnnotationTarget.ANNOTATION_CLASS,
32+
AnnotationTarget.CONSTRUCTOR,
33+
AnnotationTarget.PROPERTY_SETTER,
34+
AnnotationTarget.PROPERTY_GETTER,
35+
AnnotationTarget.TYPEALIAS,
36+
)
37+
annotation class UnstableModelixFeature(
38+
val reason: String,
39+
val intendedFinalization: String,
40+
)

model-client/build.gradle.kts

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ plugins {
44
id("com.diffplug.spotless")
55
`java-library`
66
jacoco
7+
alias(libs.plugins.npm.publish)
78
}
89

910
java {
@@ -34,6 +35,8 @@ kotlin {
3435
}
3536
}
3637
}
38+
binaries.library()
39+
generateTypeScriptDefinitions()
3740
useCommonJs()
3841
}
3942
@Suppress("UNUSED_VARIABLE", "KotlinRedundantDiagnosticSuppress")
@@ -84,6 +87,7 @@ kotlin {
8487
}
8588
}
8689
val jsMain by getting {
90+
languageSettings.optIn("kotlin.js.ExperimentalJsExport")
8791
dependencies {
8892
implementation(kotlin("stdlib-js"))
8993
implementation(npm("uuid", "^8.3.0"))
@@ -126,3 +130,82 @@ spotless {
126130
)
127131
}
128132
}
133+
134+
val productionLibraryByKotlinOutputDirectory = layout.buildDirectory.dir("compileSync/js/main/productionLibrary/kotlin")
135+
val preparedProductionLibraryOutputDirectory = layout.buildDirectory.dir("npmPublication")
136+
137+
val patchTypesScriptInProductionLibrary = tasks.register("patchTypesScriptInProductionLibrary") {
138+
dependsOn("compileProductionLibraryKotlinJs")
139+
inputs.dir(productionLibraryByKotlinOutputDirectory)
140+
outputs.dir(preparedProductionLibraryOutputDirectory)
141+
outputs.cacheIf { true }
142+
doLast {
143+
// Delete old data
144+
delete {
145+
delete(preparedProductionLibraryOutputDirectory)
146+
}
147+
148+
// Copy over library create by Kotlin
149+
copy {
150+
from(productionLibraryByKotlinOutputDirectory)
151+
into(preparedProductionLibraryOutputDirectory)
152+
}
153+
154+
// Add correct TypeScript imports and mark exports as experimental.
155+
val typescriptDeclaration =
156+
preparedProductionLibraryOutputDirectory.get().file("modelix.core-model-client.d.ts").asFile
157+
val originalTypescriptDeclarationContent = typescriptDeclaration.readLines()
158+
val experimentalDeclaration = """
159+
160+
/**
161+
* @experimental This feature is expected to be finalized with https://issues.modelix.org/issue/MODELIX-500.
162+
*/
163+
""".trimIndent()
164+
typescriptDeclaration.writer().use {
165+
it.appendLine("""import { INodeJS } from "@modelix/ts-model-api";""")
166+
.appendLine()
167+
for (line in originalTypescriptDeclarationContent) {
168+
// Only mark the parts of the client (`org.modelix.model.client2`) experimental.
169+
// Reported declarations from `org.modelix.model.api` should not be annotated as experimental.
170+
if (line.startsWith("export declare namespace org.modelix.model.client2")) {
171+
it.appendLine(experimentalDeclaration)
172+
}
173+
it.appendLine(line)
174+
}
175+
}
176+
}
177+
}
178+
179+
npmPublish {
180+
registries {
181+
register("itemis-npm-open") {
182+
uri.set("https://artifacts.itemis.cloud/repository/npm-open")
183+
System.getenv("NODE_AUTH_TOKEN").takeIf { !it.isNullOrBlank() }?.let {
184+
authToken.set(it)
185+
}
186+
}
187+
}
188+
packages {
189+
named("js") {
190+
files {
191+
// The files need to be set manually because we patch
192+
// the JS/TS produces by `compileProductionLibraryKotlinJs`
193+
// with the `patchTypesScriptInProductionLibrary` task
194+
setFrom(patchTypesScriptInProductionLibrary)
195+
}
196+
packageJson {
197+
name.set("@modelix/model-client")
198+
homepage.set("https://modelix.org/")
199+
repository {
200+
type.set("git")
201+
url.set("https://github.com/modelix/modelix.core.git")
202+
directory.set(project.name)
203+
}
204+
}
205+
dependencies {
206+
// The model client NPM package uses the types from this @modelix/ts-model-api
207+
normal("@modelix/ts-model-api", rootProject.version.toString())
208+
}
209+
}
210+
}
211+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright (c) 2023.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.modelix.model.client2
18+
19+
import INodeJS
20+
import org.modelix.kotlin.utils.UnstableModelixFeature
21+
22+
@UnstableModelixFeature(
23+
reason = "The overarching task https://issues.modelix.org/issue/MODELIX-500 is in development.",
24+
intendedFinalization = "The client is intended to be finalized when the overarching task is finished.",
25+
)
26+
@JsExport
27+
sealed interface ChangeJS {
28+
val node: INodeJS
29+
}
30+
31+
@UnstableModelixFeature(
32+
reason = "The overarching task https://issues.modelix.org/issue/MODELIX-500 is in development.",
33+
intendedFinalization = "The client is intended to be finalized when the overarching task is finished.",
34+
)
35+
@JsExport
36+
data class PropertyChanged(override val node: INodeJS, val role: String) : ChangeJS
37+
38+
@UnstableModelixFeature(
39+
reason = "The overarching task https://issues.modelix.org/issue/MODELIX-500 is in development.",
40+
intendedFinalization = "The client is intended to be finalized when the overarching task is finished.",
41+
)
42+
@JsExport
43+
data class ChildrenChanged(override val node: INodeJS, val role: String?) : ChangeJS
44+
45+
@UnstableModelixFeature(
46+
reason = "The overarching task https://issues.modelix.org/issue/MODELIX-500 is in development.",
47+
intendedFinalization = "The client is intended to be finalized when the overarching task is finished.",
48+
)
49+
@JsExport
50+
data class ReferenceChanged(override val node: INodeJS, val role: String) : ChangeJS
51+
52+
@UnstableModelixFeature(
53+
reason = "The overarching task https://issues.modelix.org/issue/MODELIX-500 is in development.",
54+
intendedFinalization = "The client is intended to be finalized when the overarching task is finished.",
55+
)
56+
@JsExport
57+
data class ContainmentChanged(override val node: INodeJS) : ChangeJS

0 commit comments

Comments
 (0)