Migration to 1.4

This commit is contained in:
Alexander Nozik 2020-08-31 11:27:44 +03:00
parent b8d775aa30
commit 57b263ec63
22 changed files with 171 additions and 183 deletions

View File

@ -1,13 +1,10 @@
plugins { plugins {
val toolsVersion = "0.6.0" id("kscience.publish") apply false
id("kscience.mpp") version toolsVersion apply false
id("kscience.jvm") version toolsVersion apply false
id("kscience.publish") version toolsVersion apply false
id("org.jetbrains.dokka") version "1.4.0-rc" id("org.jetbrains.dokka") version "1.4.0-rc"
id("org.jetbrains.changelog") version "0.4.0" id("org.jetbrains.changelog") version "0.4.0"
} }
val dataforgeVersion by extra("0.1.9-dev-1") val dataforgeVersion by extra("0.1.9-dev-2")
val bintrayRepo by extra("dataforge") val bintrayRepo by extra("dataforge")
val githubProject by extra("dataforge-core") val githubProject by extra("dataforge-core")

View File

@ -8,12 +8,16 @@ kscience{
useCoroutines() useCoroutines()
} }
repositories {
maven("https://maven.pkg.github.com/altavir/kotlin-logging")
}
kotlin { kotlin {
sourceSets { sourceSets {
val commonMain by getting { val commonMain by getting {
dependencies { dependencies {
api(project(":dataforge-meta")) api(project(":dataforge-meta"))
api("io.github.microutils:kotlin-logging:1.9.0") api("io.github.microutils:kotlin-logging:1.9.0-dev-npm")
} }
} }
val jvmMain by getting { val jvmMain by getting {

View File

@ -20,12 +20,12 @@ inline fun <reified R : Any, T : R> Data<T>.upcast(): Data<R> = upcast(R::class)
/** /**
* Check if node could be safely cast to given class * Check if node could be safely cast to given class
*/ */
expect fun <R : Any> DataNode<*>.canCast(type: KClass<out R>): Boolean internal expect fun <R : Any> DataNode<*>.canCast(type: KClass<out R>): Boolean
/** /**
* Check if data could be safely cast to given class * Check if data could be safely cast to given class
*/ */
expect fun <R : Any> Data<*>.canCast(type: KClass<out R>): Boolean internal expect fun <R : Any> Data<*>.canCast(type: KClass<out R>): Boolean
fun <R : Any> DataItem<*>.canCast(type: KClass<out R>): Boolean = when (this) { fun <R : Any> DataItem<*>.canCast(type: KClass<out R>): Boolean = when (this) {
is DataItem.Node -> node.canCast(type) is DataItem.Node -> node.canCast(type)

View File

@ -5,12 +5,12 @@ import kotlin.reflect.KClass
/** /**
* Check that node is compatible with given type meaning that each element could be cast to the type * Check that node is compatible with given type meaning that each element could be cast to the type
*/ */
actual fun <R : Any> DataNode<*>.canCast(type: KClass<out R>): Boolean { internal actual fun <R : Any> DataNode<*>.canCast(type: KClass<out R>): Boolean {
//Not supported in js yet //Not supported in js yet
return true return true
} }
actual fun <R : Any> Data<*>.canCast(type: KClass<out R>): Boolean { internal actual fun <R : Any> Data<*>.canCast(type: KClass<out R>): Boolean {
//Not supported in js yet //Not supported in js yet
return true return true
} }

View File

@ -8,28 +8,28 @@ import kotlin.reflect.full.isSuperclassOf
/** /**
* Block the thread and get data content * Block the thread and get data content
*/ */
fun <T : Any> Data<T>.get(): T = runBlocking { await() } public fun <T : Any> Data<T>.get(): T = runBlocking { await() }
/** /**
* Check that node is compatible with given type meaning that each element could be cast to the type * Check that node is compatible with given type meaning that each element could be cast to the type
*/ */
actual fun <R : Any> DataNode<*>.canCast(type: KClass<out R>): Boolean = internal actual fun <R : Any> DataNode<*>.canCast(type: KClass<out R>): Boolean =
type.isSuperclassOf(type) type.isSuperclassOf(type)
actual fun <R : Any> Data<*>.canCast(type: KClass<out R>): Boolean = internal actual fun <R : Any> Data<*>.canCast(type: KClass<out R>): Boolean =
this.type.isSubclassOf(type) this.type.isSubclassOf(type)
/** /**
* Cast the node to given type if the cast is possible or return null * Cast the node to given type if the cast is possible or return null
*/ */
fun <R : Any> Data<*>.filterIsInstance(type: KClass<out R>): Data<R>? = public fun <R : Any> Data<*>.filterIsInstance(type: KClass<out R>): Data<R>? =
if (canCast(type)) cast(type) else null if (canCast(type)) cast(type) else null
/** /**
* Filter a node by data and node type. Resulting node and its subnodes is guaranteed to have border type [type], * Filter a node by data and node type. Resulting node and its subnodes is guaranteed to have border type [type],
* but could contain empty nodes * but could contain empty nodes
*/ */
fun <R : Any> DataNode<*>.filterIsInstance(type: KClass<out R>): DataNode<R> { public fun <R : Any> DataNode<*>.filterIsInstance(type: KClass<out R>): DataNode<R> {
return when { return when {
canCast(type) -> cast(type) canCast(type) -> cast(type)
this is TypeFilteredDataNode -> origin.filterIsInstance(type) this is TypeFilteredDataNode -> origin.filterIsInstance(type)

View File

@ -0,0 +1,11 @@
package hep.dataforge.io
import hep.dataforge.meta.DFExperimental
/**
* A fire-and-forget consumer of messages
*/
@DFExperimental
public interface Consumer {
public fun consume(message: Envelope): Unit
}

View File

@ -1,21 +1,12 @@
package hep.dataforge.io package hep.dataforge.io
import hep.dataforge.meta.DFExperimental
/** /**
* An object that could respond to external messages asynchronously * An object that could respond to external messages asynchronously
*/ */
interface Responder { public interface Responder {
/** /**
* Send a request and wait for response for this specific request * Send a request and wait for response for this specific request
*/ */
suspend fun respond(request: Envelope): Envelope public suspend fun respond(request: Envelope): Envelope
} }
/**
* A fire-and-forget consumer of messages
*/
@DFExperimental
interface Consumer {
fun consume(message: Envelope): Unit
}

View File

@ -4,16 +4,13 @@ import hep.dataforge.names.Name
import hep.dataforge.names.NameToken import hep.dataforge.names.NameToken
import hep.dataforge.names.asName import hep.dataforge.names.asName
import hep.dataforge.names.plus import hep.dataforge.names.plus
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.Serializer import kotlinx.serialization.Serializer
import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.encoding.Encoder
import kotlin.collections.HashSet
import kotlin.collections.forEach
import kotlin.collections.mapValues
import kotlin.collections.removeAll
import kotlin.collections.set import kotlin.collections.set
//TODO add validator to configuration //TODO add validator to configuration
@ -24,15 +21,15 @@ public data class MetaListener(
) )
public interface ObservableMeta : Meta { public interface ObservableMeta : Meta {
fun onChange(owner: Any?, action: (name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?) -> Unit) public fun onChange(owner: Any?, action: (name: Name, oldItem: MetaItem<*>?, newItem: MetaItem<*>?) -> Unit)
fun removeListener(owner: Any?) public fun removeListener(owner: Any?)
} }
/** /**
* Mutable meta representing object state * Mutable meta representing object state
*/ */
@Serializable @Serializable
class Config : AbstractMutableMeta<Config>(), ObservableMeta { public class Config : AbstractMutableMeta<Config>(), ObservableMeta {
private val listeners = HashSet<MetaListener>() private val listeners = HashSet<MetaListener>()
@ -78,10 +75,11 @@ class Config : AbstractMutableMeta<Config>(), ObservableMeta {
override fun empty(): Config = Config() override fun empty(): Config = Config()
@OptIn(ExperimentalSerializationApi::class)
@Serializer(Config::class) @Serializer(Config::class)
companion object ConfigSerializer : KSerializer<Config> { public companion object ConfigSerializer : KSerializer<Config> {
fun empty(): Config = Config() public fun empty(): Config = Config()
override val descriptor: SerialDescriptor get() = MetaSerializer.descriptor override val descriptor: SerialDescriptor get() = MetaSerializer.descriptor
override fun deserialize(decoder: Decoder): Config { override fun deserialize(decoder: Decoder): Config {
@ -94,9 +92,9 @@ class Config : AbstractMutableMeta<Config>(), ObservableMeta {
} }
} }
operator fun Config.get(token: NameToken): MetaItem<Config>? = items[token] public operator fun Config.get(token: NameToken): MetaItem<Config>? = items[token]
fun Meta.asConfig(): Config = this as? Config ?: Config().also { builder -> public fun Meta.asConfig(): Config = this as? Config ?: Config().also { builder ->
this.items.mapValues { entry -> this.items.mapValues { entry ->
val item = entry.value val item = entry.value
builder[entry.key.asName()] = when (item) { builder[entry.key.asName()] = when (item) {

View File

@ -14,21 +14,21 @@ import kotlin.reflect.KProperty
* It is not possible to know if some property is declared by provider just by looking on [Configurable], * It is not possible to know if some property is declared by provider just by looking on [Configurable],
* this information should be provided externally. * this information should be provided externally.
*/ */
interface Configurable : Described, MutableItemProvider { public interface Configurable : Described, MutableItemProvider {
/** /**
* Backing config * Backing config
*/ */
val config: Config public val config: Config
/** /**
* Default meta item provider * Default meta item provider
*/ */
fun getDefaultItem(name: Name): MetaItem<*>? = null public fun getDefaultItem(name: Name): MetaItem<*>? = null
/** /**
* Check if property with given [name] could be assigned to [item] * Check if property with given [name] could be assigned to [item]
*/ */
fun validateItem(name: Name, item: MetaItem<*>?): Boolean { public fun validateItem(name: Name, item: MetaItem<*>?): Boolean {
val descriptor = descriptor?.get(name) val descriptor = descriptor?.get(name)
return descriptor?.validateItem(item) ?: true return descriptor?.validateItem(item) ?: true
} }
@ -53,40 +53,32 @@ interface Configurable : Described, MutableItemProvider {
} }
} }
/** public fun Configurable.getItem(key: String): MetaItem<*>? = getItem(key.toName())
* Reset the property to its default value
*/
@Deprecated("To be removed since unused", ReplaceWith("setItem(name, null)"))
fun Configurable.resetProperty(name: Name) {
setItem(name, null)
}
fun Configurable.getItem(key: String) = getItem(key.toName()) public fun Configurable.setItem(name: Name, value: Value?): Unit = setItem(name, value?.let { MetaItem.ValueItem(value) })
public fun Configurable.setItem(name: Name, meta: Meta?): Unit = setItem(name, meta?.let { MetaItem.NodeItem(meta) })
fun Configurable.setItem(name: Name, value: Value?) = setItem(name, value?.let { MetaItem.ValueItem(value) }) public fun Configurable.setItem(key: String, item: MetaItem<*>?): Unit = setItem(key.toName(), item)
fun Configurable.setItem(name: Name, meta: Meta?) = setItem(name, meta?.let { MetaItem.NodeItem(meta) })
fun Configurable.setItem(key: String, item: MetaItem<*>?) = setItem(key.toName(), item) public fun Configurable.setItem(key: String, value: Value?): Unit = setItem(key, value?.let { MetaItem.ValueItem(value) })
public fun Configurable.setItem(key: String, meta: Meta?): Unit = setItem(key, meta?.let { MetaItem.NodeItem(meta) })
fun Configurable.setItem(key: String, value: Value?) = setItem(key, value?.let { MetaItem.ValueItem(value) }) public fun <T : Configurable> T.configure(meta: Meta): T = this.apply { config.update(meta) }
fun Configurable.setItem(key: String, meta: Meta?) = setItem(key, meta?.let { MetaItem.NodeItem(meta) })
fun <T : Configurable> T.configure(meta: Meta): T = this.apply { config.update(meta) }
@DFBuilder @DFBuilder
inline fun <T : Configurable> T.configure(action: Config.() -> Unit): T = apply { config.apply(action) } public inline fun <T : Configurable> T.configure(action: Config.() -> Unit): T = apply { config.apply(action) }
/* Node delegates */ /* Node delegates */
fun Configurable.config(key: Name? = null): ReadWriteProperty<Any?, Config?> = public fun Configurable.config(key: Name? = null): ReadWriteProperty<Any?, Config?> =
config.node(key) config.node(key)
fun MutableItemProvider.node(key: Name? = null): ReadWriteProperty<Any?, Meta?> = item(key).convert( public fun MutableItemProvider.node(key: Name? = null): ReadWriteProperty<Any?, Meta?> = item(key).convert(
reader = { it.node }, reader = { it.node },
writer = { it?.let { MetaItem.NodeItem(it) } } writer = { it?.let { MetaItem.NodeItem(it) } }
) )
fun <T : Configurable> Configurable.spec( public fun <T : Configurable> Configurable.spec(
spec: Specification<T>, key: Name? = null spec: Specification<T>, key: Name? = null
): ReadWriteProperty<Any?, T?> = object : ReadWriteProperty<Any?, T?> { ): ReadWriteProperty<Any?, T?> = object : ReadWriteProperty<Any?, T?> {
override fun getValue(thisRef: Any?, property: KProperty<*>): T? { override fun getValue(thisRef: Any?, property: KProperty<*>): T? {
@ -100,7 +92,7 @@ fun <T : Configurable> Configurable.spec(
} }
} }
fun <T : Configurable> Configurable.spec( public fun <T : Configurable> Configurable.spec(
spec: Specification<T>, default: T, key: Name? = null spec: Specification<T>, default: T, key: Name? = null
): ReadWriteProperty<Any?, T> = object : ReadWriteProperty<Any?, T> { ): ReadWriteProperty<Any?, T> = object : ReadWriteProperty<Any?, T> {
override fun getValue(thisRef: Any?, property: KProperty<*>): T { override fun getValue(thisRef: Any?, property: KProperty<*>): T {

View File

@ -19,7 +19,7 @@ open class ItemDelegate(
} }
} }
fun ItemProvider.item(key: Name? = null): ItemDelegate = ItemDelegate(this, key) public fun ItemProvider.item(key: Name? = null): ItemDelegate = ItemDelegate(this, key)
//TODO add caching for sealed nodes //TODO add caching for sealed nodes
@ -29,62 +29,62 @@ fun ItemProvider.item(key: Name? = null): ItemDelegate = ItemDelegate(this, key)
/** /**
* A property delegate that uses custom key * A property delegate that uses custom key
*/ */
fun ItemProvider.value(key: Name? = null): ReadOnlyProperty<Any?, Value?> = public fun ItemProvider.value(key: Name? = null): ReadOnlyProperty<Any?, Value?> =
item(key).convert(MetaConverter.value) item(key).convert(MetaConverter.value)
fun ItemProvider.string(key: Name? = null): ReadOnlyProperty<Any?, String?> = public fun ItemProvider.string(key: Name? = null): ReadOnlyProperty<Any?, String?> =
item(key).convert(MetaConverter.string) item(key).convert(MetaConverter.string)
fun ItemProvider.boolean(key: Name? = null): ReadOnlyProperty<Any?, Boolean?> = public fun ItemProvider.boolean(key: Name? = null): ReadOnlyProperty<Any?, Boolean?> =
item(key).convert(MetaConverter.boolean) item(key).convert(MetaConverter.boolean)
fun ItemProvider.number(key: Name? = null): ReadOnlyProperty<Any?, Number?> = public fun ItemProvider.number(key: Name? = null): ReadOnlyProperty<Any?, Number?> =
item(key).convert(MetaConverter.number) item(key).convert(MetaConverter.number)
fun ItemProvider.double(key: Name? = null): ReadOnlyProperty<Any?, Double?> = public fun ItemProvider.double(key: Name? = null): ReadOnlyProperty<Any?, Double?> =
item(key).convert(MetaConverter.double) item(key).convert(MetaConverter.double)
fun ItemProvider.float(key: Name? = null): ReadOnlyProperty<Any?, Float?> = public fun ItemProvider.float(key: Name? = null): ReadOnlyProperty<Any?, Float?> =
item(key).convert(MetaConverter.float) item(key).convert(MetaConverter.float)
fun ItemProvider.int(key: Name? = null): ReadOnlyProperty<Any?, Int?> = public fun ItemProvider.int(key: Name? = null): ReadOnlyProperty<Any?, Int?> =
item(key).convert(MetaConverter.int) item(key).convert(MetaConverter.int)
fun ItemProvider.long(key: Name? = null): ReadOnlyProperty<Any?, Long?> = public fun ItemProvider.long(key: Name? = null): ReadOnlyProperty<Any?, Long?> =
item(key).convert(MetaConverter.long) item(key).convert(MetaConverter.long)
fun ItemProvider.node(key: Name? = null): ReadOnlyProperty<Any?, Meta?> = public fun ItemProvider.node(key: Name? = null): ReadOnlyProperty<Any?, Meta?> =
item(key).convert(MetaConverter.meta) item(key).convert(MetaConverter.meta)
fun ItemProvider.string(default: String, key: Name? = null): ReadOnlyProperty<Any?, String> = public fun ItemProvider.string(default: String, key: Name? = null): ReadOnlyProperty<Any?, String> =
item(key).convert(MetaConverter.string) { default } item(key).convert(MetaConverter.string) { default }
fun ItemProvider.boolean(default: Boolean, key: Name? = null): ReadOnlyProperty<Any?, Boolean> = public fun ItemProvider.boolean(default: Boolean, key: Name? = null): ReadOnlyProperty<Any?, Boolean> =
item(key).convert(MetaConverter.boolean) { default } item(key).convert(MetaConverter.boolean) { default }
fun ItemProvider.number(default: Number, key: Name? = null): ReadOnlyProperty<Any?, Number> = public fun ItemProvider.number(default: Number, key: Name? = null): ReadOnlyProperty<Any?, Number> =
item(key).convert(MetaConverter.number) { default } item(key).convert(MetaConverter.number) { default }
fun ItemProvider.double(default: Double, key: Name? = null): ReadOnlyProperty<Any?, Double> = public fun ItemProvider.double(default: Double, key: Name? = null): ReadOnlyProperty<Any?, Double> =
item(key).convert(MetaConverter.double) { default } item(key).convert(MetaConverter.double) { default }
fun ItemProvider.float(default: Float, key: Name? = null): ReadOnlyProperty<Any?, Float> = public fun ItemProvider.float(default: Float, key: Name? = null): ReadOnlyProperty<Any?, Float> =
item(key).convert(MetaConverter.float) { default } item(key).convert(MetaConverter.float) { default }
fun ItemProvider.int(default: Int, key: Name? = null): ReadOnlyProperty<Any?, Int> = public fun ItemProvider.int(default: Int, key: Name? = null): ReadOnlyProperty<Any?, Int> =
item(key).convert(MetaConverter.int) { default } item(key).convert(MetaConverter.int) { default }
fun ItemProvider.long(default: Long, key: Name? = null): ReadOnlyProperty<Any?, Long> = public fun ItemProvider.long(default: Long, key: Name? = null): ReadOnlyProperty<Any?, Long> =
item(key).convert(MetaConverter.long) { default } item(key).convert(MetaConverter.long) { default }
inline fun <reified E : Enum<E>> ItemProvider.enum(default: E, key: Name? = null): ReadOnlyProperty<Any?, E> = public inline fun <reified E : Enum<E>> ItemProvider.enum(default: E, key: Name? = null): ReadOnlyProperty<Any?, E> =
item(key).convert(MetaConverter.enum()) { default } item(key).convert(MetaConverter.enum()) { default }
fun ItemProvider.string(key: Name? = null, default: () -> String): ReadOnlyProperty<Any?, String> = public fun ItemProvider.string(key: Name? = null, default: () -> String): ReadOnlyProperty<Any?, String> =
item(key).convert(MetaConverter.string, default) item(key).convert(MetaConverter.string, default)
fun ItemProvider.boolean(key: Name? = null, default: () -> Boolean): ReadOnlyProperty<Any?, Boolean> = public fun ItemProvider.boolean(key: Name? = null, default: () -> Boolean): ReadOnlyProperty<Any?, Boolean> =
item(key).convert(MetaConverter.boolean, default) item(key).convert(MetaConverter.boolean, default)
fun ItemProvider.number(key: Name? = null, default: () -> Number): ReadOnlyProperty<Any?, Number> = public fun ItemProvider.number(key: Name? = null, default: () -> Number): ReadOnlyProperty<Any?, Number> =
item(key).convert(MetaConverter.number, default) item(key).convert(MetaConverter.number, default)

View File

@ -15,7 +15,7 @@ import kotlinx.serialization.json.*
/** /**
* @param descriptor reserved for custom serialization in future * @param descriptor reserved for custom serialization in future
*/ */
fun Value.toJson(descriptor: ValueDescriptor? = null): JsonElement { public fun Value.toJson(descriptor: ValueDescriptor? = null): JsonElement {
return if (isList()) { return if (isList()) {
JsonArray(list.map { it.toJson() }) JsonArray(list.map { it.toJson() })
} else { } else {
@ -82,11 +82,11 @@ private fun Meta.toJsonWithIndex(descriptor: NodeDescriptor?, indexValue: String
return JsonObject(elementMap) return JsonObject(elementMap)
} }
fun Meta.toJson(descriptor: NodeDescriptor? = null): JsonObject = toJsonWithIndex(descriptor, null) public fun Meta.toJson(descriptor: NodeDescriptor? = null): JsonObject = toJsonWithIndex(descriptor, null)
fun JsonObject.toMeta(descriptor: NodeDescriptor? = null): JsonMeta = JsonMeta(this, descriptor) public fun JsonObject.toMeta(descriptor: NodeDescriptor? = null): JsonMeta = JsonMeta(this, descriptor)
fun JsonPrimitive.toValue(descriptor: ValueDescriptor?): Value { public fun JsonPrimitive.toValue(descriptor: ValueDescriptor?): Value {
return when (this) { return when (this) {
JsonNull -> Null JsonNull -> Null
else -> { else -> {
@ -99,7 +99,7 @@ fun JsonPrimitive.toValue(descriptor: ValueDescriptor?): Value {
} }
} }
fun JsonElement.toMetaItem(descriptor: ItemDescriptor? = null): MetaItem<JsonMeta> = when (this) { public fun JsonElement.toMetaItem(descriptor: ItemDescriptor? = null): MetaItem<JsonMeta> = when (this) {
is JsonPrimitive -> { is JsonPrimitive -> {
val value = this.toValue(descriptor as? ValueDescriptor) val value = this.toValue(descriptor as? ValueDescriptor)
MetaItem.ValueItem(value) MetaItem.ValueItem(value)
@ -129,7 +129,7 @@ fun JsonElement.toMetaItem(descriptor: ItemDescriptor? = null): MetaItem<JsonMet
/** /**
* A meta wrapping json object * A meta wrapping json object
*/ */
class JsonMeta(val json: JsonObject, val descriptor: NodeDescriptor? = null) : MetaBase() { public class JsonMeta(private val json: JsonObject, private val descriptor: NodeDescriptor? = null) : MetaBase() {
private fun buildItems(): Map<NameToken, MetaItem<JsonMeta>> { private fun buildItems(): Map<NameToken, MetaItem<JsonMeta>> {
val map = LinkedHashMap<NameToken, MetaItem<JsonMeta>>() val map = LinkedHashMap<NameToken, MetaItem<JsonMeta>>()
@ -173,10 +173,10 @@ class JsonMeta(val json: JsonObject, val descriptor: NodeDescriptor? = null) : M
override val items: Map<NameToken, MetaItem<JsonMeta>> by lazy(::buildItems) override val items: Map<NameToken, MetaItem<JsonMeta>> by lazy(::buildItems)
companion object { public companion object {
/** /**
* A key representing top-level json array of nodes, which could not be directly represented by a meta node * A key representing top-level json array of nodes, which could not be directly represented by a meta node
*/ */
const val JSON_ARRAY_KEY = "@jsonArray" public const val JSON_ARRAY_KEY: String = "@jsonArray"
} }
} }

View File

@ -7,9 +7,9 @@ import hep.dataforge.names.NameToken
* A meta laminate consisting of multiple immutable meta layers. For mutable front layer, use [Scheme]. * A meta laminate consisting of multiple immutable meta layers. For mutable front layer, use [Scheme].
* If [layers] list contains a [Laminate] it is flat-mapped. * If [layers] list contains a [Laminate] it is flat-mapped.
*/ */
class Laminate(layers: List<Meta>) : MetaBase() { public class Laminate(layers: List<Meta>) : MetaBase() {
val layers: List<Meta> = layers.flatMap { public val layers: List<Meta> = layers.flatMap {
if (it is Laminate) { if (it is Laminate) {
it.layers it.layers
} else { } else {
@ -17,7 +17,7 @@ class Laminate(layers: List<Meta>) : MetaBase() {
} }
} }
constructor(vararg layers: Meta?) : this(layers.filterNotNull()) public constructor(vararg layers: Meta?) : this(layers.filterNotNull())
override val items: Map<NameToken, MetaItem<Meta>> by lazy { override val items: Map<NameToken, MetaItem<Meta>> by lazy {
layers.map { it.items.keys }.flatten().associateWith { key -> layers.map { it.items.keys }.flatten().associateWith { key ->
@ -28,21 +28,21 @@ class Laminate(layers: List<Meta>) : MetaBase() {
/** /**
* Generate sealed meta using [mergeRule] * Generate sealed meta using [mergeRule]
*/ */
fun merge(): SealedMeta { public fun merge(): SealedMeta {
val items = layers.map { it.items.keys }.flatten().associateWith { key -> val items = layers.map { it.items.keys }.flatten().associateWith { key ->
layers.asSequence().map { it.items[key] }.filterNotNull().merge() layers.asSequence().map { it.items[key] }.filterNotNull().merge()
} }
return SealedMeta(items) return SealedMeta(items)
} }
companion object { public companion object {
/** /**
* The default rule which always uses the first found item in sequence alongside with its children. * The default rule which always uses the first found item in sequence alongside with its children.
* *
* TODO add picture * TODO add picture
*/ */
val replaceRule: (Sequence<MetaItem<*>>) -> MetaItem<SealedMeta> = { it.first().seal() } public val replaceRule: (Sequence<MetaItem<*>>) -> MetaItem<SealedMeta> = { it.first().seal() }
private fun Sequence<MetaItem<*>>.merge(): MetaItem<SealedMeta> { private fun Sequence<MetaItem<*>>.merge(): MetaItem<SealedMeta> {
return when { return when {
@ -76,14 +76,14 @@ class Laminate(layers: List<Meta>) : MetaBase() {
* The values a replaced but meta children are joined * The values a replaced but meta children are joined
* TODO add picture * TODO add picture
*/ */
val mergeRule: (Sequence<MetaItem<*>>) -> MetaItem<SealedMeta> = { it.merge() } public val mergeRule: (Sequence<MetaItem<*>>) -> MetaItem<SealedMeta> = { it.merge() }
} }
} }
/** /**
* Performance optimized version of get method * Performance optimized version of get method
*/ */
fun Laminate.getFirst(name: Name): MetaItem<*>? { public fun Laminate.getFirst(name: Name): MetaItem<*>? {
layers.forEach { layer -> layers.forEach { layer ->
layer[name]?.let { return it } layer[name]?.let { return it }
} }
@ -93,11 +93,11 @@ fun Laminate.getFirst(name: Name): MetaItem<*>? {
/** /**
* Create a new [Laminate] adding given layer to the top * Create a new [Laminate] adding given layer to the top
*/ */
fun Laminate.withTop(meta: Meta): Laminate = Laminate(listOf(meta) + layers) public fun Laminate.withTop(meta: Meta): Laminate = Laminate(listOf(meta) + layers)
/** /**
* Create a new [Laminate] adding given layer to the bottom * Create a new [Laminate] adding given layer to the bottom
*/ */
fun Laminate.withBottom(meta: Meta): Laminate = Laminate(layers + meta) public fun Laminate.withBottom(meta: Meta): Laminate = Laminate(layers + meta)
//TODO add custom rules for Laminate merge //TODO add custom rules for Laminate merge

View File

@ -5,6 +5,7 @@ import hep.dataforge.meta.MetaItem.NodeItem
import hep.dataforge.meta.MetaItem.ValueItem import hep.dataforge.meta.MetaItem.ValueItem
import hep.dataforge.names.* import hep.dataforge.names.*
import hep.dataforge.values.* import hep.dataforge.values.*
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.Serializer import kotlinx.serialization.Serializer
@ -19,18 +20,19 @@ import kotlinx.serialization.encoding.Encoder
* * a [NodeItem] (node) * * a [NodeItem] (node)
*/ */
@Serializable @Serializable
sealed class MetaItem<out M : Meta> { public sealed class MetaItem<out M : Meta> {
abstract override fun equals(other: Any?): Boolean abstract override fun equals(other: Any?): Boolean
abstract override fun hashCode(): Int abstract override fun hashCode(): Int
@Serializable @Serializable
class ValueItem(val value: Value) : MetaItem<Nothing>() { public class ValueItem(public val value: Value) : MetaItem<Nothing>() {
override fun toString(): String = value.toString() override fun toString(): String = value.toString()
@OptIn(ExperimentalSerializationApi::class)
@Serializer(ValueItem::class) @Serializer(ValueItem::class)
companion object : KSerializer<ValueItem> { public companion object : KSerializer<ValueItem> {
override val descriptor: SerialDescriptor get() = ValueSerializer.descriptor override val descriptor: SerialDescriptor get() = ValueSerializer.descriptor
override fun deserialize(decoder: Decoder): ValueItem = ValueItem(ValueSerializer.deserialize(decoder)) override fun deserialize(decoder: Decoder): ValueItem = ValueItem(ValueSerializer.deserialize(decoder))
@ -50,12 +52,13 @@ sealed class MetaItem<out M : Meta> {
} }
@Serializable @Serializable
class NodeItem<M : Meta>(@Serializable(MetaSerializer::class) val node: M) : MetaItem<M>() { public class NodeItem<M : Meta>(@Serializable(MetaSerializer::class) public val node: M) : MetaItem<M>() {
//Fixing serializer for node could cause class cast problems, but it should not since Meta descendants are not serializeable //Fixing serializer for node could cause class cast problems, but it should not since Meta descendants are not serializeable
override fun toString(): String = node.toString() override fun toString(): String = node.toString()
@OptIn(ExperimentalSerializationApi::class)
@Serializer(NodeItem::class) @Serializer(NodeItem::class)
companion object : KSerializer<NodeItem<out Meta>> { public companion object : KSerializer<NodeItem<out Meta>> {
override val descriptor: SerialDescriptor get() = MetaSerializer.descriptor override val descriptor: SerialDescriptor get() = MetaSerializer.descriptor
override fun deserialize(decoder: Decoder): NodeItem<*> = NodeItem(MetaSerializer.deserialize(decoder)) override fun deserialize(decoder: Decoder): NodeItem<*> = NodeItem(MetaSerializer.deserialize(decoder))
@ -70,8 +73,8 @@ sealed class MetaItem<out M : Meta> {
override fun hashCode(): Int = node.hashCode() override fun hashCode(): Int = node.hashCode()
} }
companion object { public companion object {
fun of(arg: Any?): MetaItem<*> { public fun of(arg: Any?): MetaItem<*> {
return when (arg) { return when (arg) {
null -> ValueItem(Null) null -> ValueItem(Null)
is MetaItem<*> -> arg is MetaItem<*> -> arg
@ -82,19 +85,19 @@ sealed class MetaItem<out M : Meta> {
} }
} }
fun Value.asMetaItem() = ValueItem(this) public fun Value.asMetaItem(): ValueItem = ValueItem(this)
fun <M:Meta> M.asMetaItem() = NodeItem(this) public fun <M:Meta> M.asMetaItem(): NodeItem<M> = NodeItem(this)
/** /**
* The object that could be represented as [Meta]. Meta provided by [toMeta] method should fully represent object state. * The object that could be represented as [Meta]. Meta provided by [toMeta] method should fully represent object state.
* Meaning that two states with the same meta are equal. * Meaning that two states with the same meta are equal.
*/ */
interface MetaRepr { public interface MetaRepr {
fun toMeta(): Meta public fun toMeta(): Meta
} }
interface ItemProvider{ public interface ItemProvider{
fun getItem(name: Name): MetaItem<*>? public fun getItem(name: Name): MetaItem<*>?
} }
/** /**
@ -104,11 +107,11 @@ interface ItemProvider{
* *
* * Same name siblings are supported via elements with the same [Name] but different queries * * Same name siblings are supported via elements with the same [Name] but different queries
*/ */
interface Meta : MetaRepr, ItemProvider { public interface Meta : MetaRepr, ItemProvider {
/** /**
* Top level items of meta tree * Top level items of meta tree
*/ */
val items: Map<NameToken, MetaItem<*>> public val items: Map<NameToken, MetaItem<*>>
override fun getItem(name: Name): MetaItem<*>? { override fun getItem(name: Name): MetaItem<*>? {
if (name.isEmpty()) return NodeItem(this) if (name.isEmpty()) return NodeItem(this)
@ -129,15 +132,15 @@ interface Meta : MetaRepr, ItemProvider {
override fun toString(): String override fun toString(): String
companion object { public companion object {
const val TYPE = "meta" public const val TYPE: String = "meta"
/** /**
* A key for single value node * A key for single value node
*/ */
const val VALUE_KEY = "@value" public const val VALUE_KEY: String = "@value"
val EMPTY: Meta = object: MetaBase() { public val EMPTY: Meta = object: MetaBase() {
override val items: Map<NameToken, MetaItem<*>> = emptyMap() override val items: Map<NameToken, MetaItem<*>> = emptyMap()
} }
} }
@ -150,19 +153,19 @@ interface Meta : MetaRepr, ItemProvider {
* *
* If [name] is empty return current [Meta] as a [NodeItem] * If [name] is empty return current [Meta] as a [NodeItem]
*/ */
operator fun Meta?.get(name: Name): MetaItem<*>? = this?.getItem(name) public operator fun Meta?.get(name: Name): MetaItem<*>? = this?.getItem(name)
operator fun Meta?.get(token: NameToken): MetaItem<*>? = this?.items?.get(token) public operator fun Meta?.get(token: NameToken): MetaItem<*>? = this?.items?.get(token)
/** /**
* Parse [Name] from [key] using full name notation and pass it to [Meta.get] * Parse [Name] from [key] using full name notation and pass it to [Meta.get]
*/ */
operator fun Meta?.get(key: String): MetaItem<*>? = get(key.toName()) public operator fun Meta?.get(key: String): MetaItem<*>? = get(key.toName())
/** /**
* Get a sequence of [Name]-[Value] pairs * Get a sequence of [Name]-[Value] pairs
*/ */
fun Meta.values(): Sequence<Pair<Name, Value>> { public fun Meta.values(): Sequence<Pair<Name, Value>> {
return items.asSequence().flatMap { (key, item) -> return items.asSequence().flatMap { (key, item) ->
when (item) { when (item) {
is ValueItem -> sequenceOf(key.asName() to item.value) is ValueItem -> sequenceOf(key.asName() to item.value)
@ -174,7 +177,7 @@ fun Meta.values(): Sequence<Pair<Name, Value>> {
/** /**
* Get a sequence of all [Name]-[MetaItem] pairs for all items including nodes * Get a sequence of all [Name]-[MetaItem] pairs for all items including nodes
*/ */
fun Meta.sequence(): Sequence<Pair<Name, MetaItem<*>>> { public fun Meta.sequence(): Sequence<Pair<Name, MetaItem<*>>> {
return sequence { return sequence {
items.forEach { (key, item) -> items.forEach { (key, item) ->
yield(key.asName() to item) yield(key.asName() to item)
@ -187,33 +190,33 @@ fun Meta.sequence(): Sequence<Pair<Name, MetaItem<*>>> {
} }
} }
operator fun Meta.iterator(): Iterator<Pair<Name, MetaItem<*>>> = sequence().iterator() public operator fun Meta.iterator(): Iterator<Pair<Name, MetaItem<*>>> = sequence().iterator()
/** /**
* A meta node that ensures that all of its descendants has at least the same type * A meta node that ensures that all of its descendants has at least the same type
*/ */
interface MetaNode<out M : MetaNode<M>> : Meta { public interface MetaNode<out M : MetaNode<M>> : Meta {
override val items: Map<NameToken, MetaItem<M>> override val items: Map<NameToken, MetaItem<M>>
} }
/** /**
* The same as [Meta.get], but with specific node type * The same as [Meta.get], but with specific node type
*/ */
operator fun <M : MetaNode<M>> M?.get(name: Name): MetaItem<M>? = if( this == null) { public operator fun <M : MetaNode<M>> M?.get(name: Name): MetaItem<M>? = if( this == null) {
null null
} else { } else {
@Suppress("UNCHECKED_CAST", "ReplaceGetOrSet") @Suppress("UNCHECKED_CAST", "ReplaceGetOrSet")
(this as Meta).get(name) as MetaItem<M>? // Do not change (this as Meta).get(name) as MetaItem<M>? // Do not change
} }
operator fun <M : MetaNode<M>> M?.get(key: String): MetaItem<M>? = this[key.toName()] public operator fun <M : MetaNode<M>> M?.get(key: String): MetaItem<M>? = this[key.toName()]
operator fun <M : MetaNode<M>> M?.get(key: NameToken): MetaItem<M>? = this[key.asName()] public operator fun <M : MetaNode<M>> M?.get(key: NameToken): MetaItem<M>? = this[key.asName()]
/** /**
* Equals, hashcode and to string for any meta * Equals, hashcode and to string for any meta
*/ */
abstract class MetaBase : Meta { public abstract class MetaBase : Meta {
override fun equals(other: Any?): Boolean = if (other is Meta) { override fun equals(other: Any?): Boolean = if (other is Meta) {
this.items == other.items this.items == other.items
@ -229,24 +232,24 @@ abstract class MetaBase : Meta {
/** /**
* Equals and hash code implementation for meta node * Equals and hash code implementation for meta node
*/ */
abstract class AbstractMetaNode<M : MetaNode<M>> : MetaNode<M>, MetaBase() public abstract class AbstractMetaNode<M : MetaNode<M>> : MetaNode<M>, MetaBase()
/** /**
* The meta implementation which is guaranteed to be immutable. * The meta implementation which is guaranteed to be immutable.
* *
* If the argument is possibly mutable node, it is copied on creation * If the argument is possibly mutable node, it is copied on creation
*/ */
class SealedMeta internal constructor( public class SealedMeta internal constructor(
override val items: Map<NameToken, MetaItem<SealedMeta>> override val items: Map<NameToken, MetaItem<SealedMeta>>
) : AbstractMetaNode<SealedMeta>() ) : AbstractMetaNode<SealedMeta>()
/** /**
* Generate sealed node from [this]. If it is already sealed return it as is * Generate sealed node from [this]. If it is already sealed return it as is
*/ */
fun Meta.seal(): SealedMeta = this as? SealedMeta ?: SealedMeta(items.mapValues { entry -> entry.value.seal() }) public fun Meta.seal(): SealedMeta = this as? SealedMeta ?: SealedMeta(items.mapValues { entry -> entry.value.seal() })
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
fun MetaItem<*>.seal(): MetaItem<SealedMeta> = when (this) { public fun MetaItem<*>.seal(): MetaItem<SealedMeta> = when (this) {
is ValueItem -> this is ValueItem -> this
is NodeItem -> NodeItem(node.seal()) is NodeItem -> NodeItem(node.seal())
} }
@ -254,32 +257,32 @@ fun MetaItem<*>.seal(): MetaItem<SealedMeta> = when (this) {
/** /**
* Unsafe methods to access values and nodes directly from [MetaItem] * Unsafe methods to access values and nodes directly from [MetaItem]
*/ */
val MetaItem<*>?.value: Value? public val MetaItem<*>?.value: Value?
get() = (this as? ValueItem)?.value get() = (this as? ValueItem)?.value
?: (this?.node?.get(VALUE_KEY) as? ValueItem)?.value ?: (this?.node?.get(VALUE_KEY) as? ValueItem)?.value
val MetaItem<*>?.string get() = value?.string public val MetaItem<*>?.string: String? get() = value?.string
val MetaItem<*>?.boolean get() = value?.boolean public val MetaItem<*>?.boolean: Boolean? get() = value?.boolean
val MetaItem<*>?.number get() = value?.number public val MetaItem<*>?.number: Number? get() = value?.number
val MetaItem<*>?.double get() = number?.toDouble() public val MetaItem<*>?.double: Double? get() = number?.toDouble()
val MetaItem<*>?.float get() = number?.toFloat() public val MetaItem<*>?.float: Float? get() = number?.toFloat()
val MetaItem<*>?.int get() = number?.toInt() public val MetaItem<*>?.int: Int? get() = number?.toInt()
val MetaItem<*>?.long get() = number?.toLong() public val MetaItem<*>?.long: Long? get() = number?.toLong()
val MetaItem<*>?.short get() = number?.toShort() public val MetaItem<*>?.short: Short? get() = number?.toShort()
inline fun <reified E : Enum<E>> MetaItem<*>?.enum(): E? = if (this is ValueItem && this.value is EnumValue<*>) { public inline fun <reified E : Enum<E>> MetaItem<*>?.enum(): E? = if (this is ValueItem && this.value is EnumValue<*>) {
this.value.value as E this.value.value as E
} else { } else {
string?.let { enumValueOf<E>(it) } string?.let { enumValueOf<E>(it) }
} }
val MetaItem<*>.stringList get() = value?.list?.map { it.string } public val MetaItem<*>.stringList: List<String>? get() = value?.list?.map { it.string }
val <M : Meta> MetaItem<M>?.node: M? public val <M : Meta> MetaItem<M>?.node: M?
get() = when (this) { get() = when (this) {
null -> null null -> null
is ValueItem -> null//error("Trying to interpret value meta item as node item") is ValueItem -> null//error("Trying to interpret value meta item as node item")
is NodeItem -> node is NodeItem -> node
} }
fun Meta.isEmpty() = this === Meta.EMPTY || this.items.isEmpty() public fun Meta.isEmpty(): Boolean = this === Meta.EMPTY || this.items.isEmpty()

View File

@ -4,19 +4,19 @@ plugins {
kotlin { kotlin {
sourceSets { sourceSets {
val commonMain by getting { commonMain {
dependencies { dependencies {
api(project(":dataforge-workspace")) api(project(":dataforge-workspace"))
implementation(kotlin("scripting-common")) implementation(kotlin("scripting-common"))
} }
} }
val jvmMain by getting { jvmMain{
dependencies { dependencies {
implementation(kotlin("scripting-jvm-host")) implementation(kotlin("scripting-jvm-host"))
implementation(kotlin("scripting-jvm")) implementation(kotlin("scripting-jvm"))
} }
} }
val jvmTest by getting { jvmTest {
dependencies { dependencies {
implementation("ch.qos.logback:logback-classic:1.2.3") implementation("ch.qos.logback:logback-classic:1.2.3")
} }

View File

@ -1,4 +0,0 @@
package hep.dataforge.scripting
internal object Placeholder {
}

View File

@ -13,15 +13,18 @@ import kotlin.script.experimental.jvm.dependenciesFromCurrentContext
import kotlin.script.experimental.jvm.jvm import kotlin.script.experimental.jvm.jvm
import kotlin.script.experimental.jvmhost.BasicJvmScriptingHost import kotlin.script.experimental.jvmhost.BasicJvmScriptingHost
object Builders { public object Builders {
fun buildWorkspace(source: SourceCode, context: Context = Global): Workspace { private fun buildWorkspace(source: SourceCode, context: Context = Global): Workspace {
val builder = SimpleWorkspaceBuilder(context) val builder = SimpleWorkspaceBuilder(context)
val workspaceScriptConfiguration = ScriptCompilationConfiguration { val workspaceScriptConfiguration = ScriptCompilationConfiguration {
baseClass(Any::class) // baseClass(Any::class)
implicitReceivers(WorkspaceBuilder::class) implicitReceivers(WorkspaceBuilder::class)
defaultImports("hep.dataforge.workspace.*") defaultImports(
"hep.dataforge.meta.*",
"hep.dataforge.workspace.*"
)
jvm { jvm {
dependenciesFromCurrentContext(wholeClasspath = true) dependenciesFromCurrentContext(wholeClasspath = true)
} }
@ -49,7 +52,7 @@ object Builders {
return builder.build() return builder.build()
} }
fun buildWorkspace(file: File): Workspace = buildWorkspace(file.toScriptSource()) public fun buildWorkspace(file: File): Workspace = buildWorkspace(file.toScriptSource())
fun buildWorkspace(string: String): Workspace = buildWorkspace(string.toScriptSource()) public fun buildWorkspace(string: String): Workspace = buildWorkspace(string.toScriptSource())
} }

View File

@ -4,7 +4,7 @@ plugins {
kotlin { kotlin {
sourceSets { sourceSets {
val commonMain by getting{ commonMain{
dependencies { dependencies {
api(project(":dataforge-context")) api(project(":dataforge-context"))
api(project(":dataforge-data")) api(project(":dataforge-data"))

Binary file not shown.

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

21
gradlew.bat vendored
View File

@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1 %JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init if "%ERRORLEVEL%" == "0" goto execute
echo. echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@ -54,7 +54,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=% set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init if exist "%JAVA_EXE%" goto execute
echo. echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@ -64,21 +64,6 @@ echo location of your Java installation.
goto fail goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute :execute
@rem Setup the command line @rem Setup the command line
@ -86,7 +71,7 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle @rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end :end
@rem End local scope for the variables with windows NT shell @rem End local scope for the variables with windows NT shell

View File

@ -5,12 +5,20 @@ pluginManagement {
gradlePluginPortal() gradlePluginPortal()
maven("https://dl.bintray.com/kotlin/kotlin-eap") maven("https://dl.bintray.com/kotlin/kotlin-eap")
maven("https://dl.bintray.com/kotlin/kotlinx") maven("https://dl.bintray.com/kotlin/kotlinx")
maven("https://dl.bintray.com/mipt-npm/scientifik")
maven("https://dl.bintray.com/mipt-npm/kscience") maven("https://dl.bintray.com/mipt-npm/kscience")
maven("https://dl.bintray.com/mipt-npm/dev") maven("https://dl.bintray.com/mipt-npm/dev")
} }
val toolsVersion = "0.6.0" val toolsVersion = "0.6.0"
val kotlinVersion = "1.4.0"
plugins {
kotlin("jvm") version kotlinVersion
id("scientifik.mpp") version toolsVersion
id("scientifik.jvm") version toolsVersion
id("scientifik.js") version toolsVersion
id("scientifik.publish") version toolsVersion
}
resolutionStrategy { resolutionStrategy {
eachPlugin { eachPlugin {