Descriptor updates and utilities

This commit is contained in:
Alexander Nozik 2021-08-06 12:29:48 +03:00
parent 28a6914747
commit e432b07201
15 changed files with 132 additions and 569 deletions

View File

@ -1,6 +1,9 @@
name: Gradle build
on: [ push ]
on:
push:
branches: [ dev, master ]
pull_request:
jobs:
build:
@ -8,23 +11,22 @@ jobs:
matrix:
os: [ macOS-latest, windows-latest ]
runs-on: ${{matrix.os}}
timeout-minutes: 30
timeout-minutes: 40
steps:
- name: Checkout the repo
uses: actions/checkout@v2
- name: Set up JDK 11
uses: DeLaGuardo/setup-graalvm@4.0
with:
graalvm: 21.1.0
graalvm: 21.2.0
java: java11
arch: amd64
- name: Add msys to path
if: matrix.os == 'windows-latest'
run: SETX PATH "%PATH%;C:\msys64\mingw64\bin"
- name: Cache gradle
uses: actions/cache@v2
with:
path: ~/.gradle/caches
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
restore-keys: |
${{ runner.os }}-gradle-
@ -36,4 +38,4 @@ jobs:
restore-keys: |
${{ runner.os }}-gradle-
- name: Build
run: ./gradlew build --no-daemon --stacktrace
run: ./gradlew build --build-cache --no-daemon --stacktrace

View File

@ -2,39 +2,27 @@ name: Dokka publication
on:
push:
branches:
- master
branches: [ master ]
jobs:
build:
runs-on: ubuntu-20.04
timeout-minutes: 40
steps:
- name: Checkout the repo
uses: actions/checkout@v2
- name: Set up JDK 11
uses: DeLaGuardo/setup-graalvm@4.0
- uses: actions/checkout@v2
- uses: DeLaGuardo/setup-graalvm@4.0
with:
graalvm: 21.1.0
graalvm: 21.2.0
java: java11
arch: amd64
- name: Cache gradle
uses: actions/cache@v2
- uses: actions/cache@v2
with:
path: ~/.gradle/caches
key: ubuntu-20.04-gradle-${{ hashFiles('*.gradle.kts') }}
restore-keys: |
ubuntu-20.04-gradle-
- name: Cache konan
uses: actions/cache@v2
with:
path: ~/.konan
key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Build
run: ./gradlew dokkaHtmlMultiModule --no-daemon --no-parallel --stacktrace
- name: Deploy to GitHub Pages
uses: JamesIves/github-pages-deploy-action@4.1.0
- run: ./gradlew dokkaHtmlMultiModule --build-cache --no-daemon --no-parallel --stacktrace
- uses: JamesIves/github-pages-deploy-action@4.1.0
with:
branch: gh-pages
folder: build/dokka/htmlMultiModule

View File

@ -3,8 +3,7 @@ name: Gradle publish
on:
workflow_dispatch:
release:
types:
- created
types: [ created ]
jobs:
publish:
@ -20,16 +19,15 @@ jobs:
- name: Set up JDK 11
uses: DeLaGuardo/setup-graalvm@4.0
with:
graalvm: 21.1.0
graalvm: 21.2.0
java: java11
arch: amd64
- name: Add msys to path
if: matrix.os == 'windows-latest'
run: SETX PATH "%PATH%;C:\msys64\mingw64\bin"
- name: Cache gradle
uses: actions/cache@v2
with:
path: ~/.gradle/caches
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
restore-keys: |
${{ runner.os }}-gradle-
@ -42,20 +40,14 @@ jobs:
${{ runner.os }}-gradle-
- name: Publish Windows Artifacts
if: matrix.os == 'windows-latest'
shell: cmd
run: >
./gradlew release --no-daemon
-Ppublishing.enabled=true
-Ppublishing.github.user=${{ secrets.PUBLISHING_GITHUB_USER }}
-Ppublishing.github.token=${{ secrets.PUBLISHING_GITHUB_TOKEN }}
-Ppublishing.space.user=${{ secrets.PUBLISHING_SPACE_USER }}
-Ppublishing.space.token=${{ secrets.PUBLISHING_SPACE_TOKEN }}
./gradlew release --no-daemon --build-cache -Ppublishing.enabled=true
-Ppublishing.space.user=${{ secrets.SPACE_APP_ID }}
-Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }}
- name: Publish Mac Artifacts
if: matrix.os == 'macOS-latest'
run: >
./gradlew release --no-daemon
-Ppublishing.enabled=true
-Ppublishing.platform=macosX64
-Ppublishing.github.user=${{ secrets.PUBLISHING_GITHUB_USER }}
-Ppublishing.github.token=${{ secrets.PUBLISHING_GITHUB_TOKEN }}
-Ppublishing.space.user=${{ secrets.PUBLISHING_SPACE_USER }}
-Ppublishing.space.token=${{ secrets.PUBLISHING_SPACE_TOKEN }}
./gradlew release --no-daemon --build-cache -Ppublishing.enabled=true -Ppublishing.platform=macosX64
-Ppublishing.space.user=${{ secrets.SPACE_APP_ID }}
-Ppublishing.space.token=${{ secrets.SPACE_APP_SECRET }}

View File

@ -14,10 +14,8 @@
- **API breaking** `String.toName()` is replaced by `Name.parse()`
- **API breaking** Configurable`config` changed to `meta`
### Deprecated
- Direct use of `Config`
### Removed
- `Config`
- Public PluginManager mutability
- Tables and tables-exposed moved to the separate project `tables.kt`
- BinaryMetaFormat. Use CBOR encoding instead

View File

@ -4,7 +4,7 @@ plugins {
allprojects {
group = "space.kscience"
version = "0.5.0-dev-7"
version = "0.5.0-dev-9"
}
subprojects {

View File

@ -91,9 +91,9 @@ public fun JsonPrimitive.toValue(descriptor: MetaDescriptor?): Value {
}
/**
* Turn this [JsonArray] into a [ListValue] with recursion or return null if it contains objects
* Turn this [JsonElement] into a [ListValue] with recursion or return null if it contains objects
*/
public fun JsonElement.toValueOrNull(descriptor: MetaDescriptor?): Value? = when (this) {
private fun JsonElement.toValueOrNull(descriptor: MetaDescriptor?): Value? = when (this) {
is JsonPrimitive -> toValue(descriptor)
is JsonObject -> get(Meta.VALUE_KEY)?.toValueOrNull(descriptor)
is JsonArray -> {

View File

@ -3,6 +3,7 @@ package space.kscience.dataforge.meta
import kotlinx.serialization.Serializable
import space.kscience.dataforge.names.NameToken
import space.kscience.dataforge.values.Value
import space.kscience.dataforge.values.asValue
/**
* The meta implementation which is guaranteed to be immutable.
@ -32,6 +33,15 @@ public fun Meta.seal(): SealedMeta = this as? SealedMeta ?: SealedMeta(
@Suppress("FunctionName")
public fun Meta(value: Value): SealedMeta = SealedMeta(value, emptyMap())
@Suppress("FunctionName")
public fun Meta(value: Number): SealedMeta = Meta(value.asValue())
@Suppress("FunctionName")
public fun Meta(value: String): SealedMeta = Meta(value.asValue())
@Suppress("FunctionName")
public fun Meta(value: Boolean): SealedMeta = Meta(value.asValue())
@Suppress("FunctionName")
public inline fun Meta(builder: MutableMeta.() -> Unit): SealedMeta =
MutableMeta(builder).seal()

View File

@ -41,7 +41,7 @@ public interface Specification<out T : Any> : ReadOnlySpecification<T> {
/**
* Update a [MutableMeta] using given specification
*/
public fun <T : Any> MutableMeta.update(
public fun <T : Any> MutableMeta.updateWith(
spec: Specification<T>,
action: T.() -> Unit
): T = spec.write(this).apply(action)
@ -50,7 +50,7 @@ public fun <T : Any> MutableMeta.update(
/**
* Update configuration using given specification
*/
public fun <T : Any> Configurable.update(
public fun <T : Any> Configurable.updateWith(
spec: Specification<T>,
action: T.() -> Unit,
): T = spec.write(meta).apply(action)

View File

@ -1,127 +0,0 @@
//package space.kscience.dataforge.meta.descriptors
//
//import space.kscience.dataforge.meta.*
//import space.kscience.dataforge.misc.DFBuilder
//import space.kscience.dataforge.names.*
//import space.kscience.dataforge.values.Value
//
///**
// * A common parent for [ValueDescriptor] and [NodeDescriptor]. Describes a single [TypedMetaItem] or a group of same-name-siblings.
// */
//public sealed interface ItemDescriptor: MetaRepr {
//
// /**
// * True if same name siblings with this name are allowed
// */
// public val multiple: Boolean
//
// /**
// * The item description text
// */
// public val info: String?
//
// /**
// * True if the item is required
// */
// public val required: Boolean
//
//
// /**
// * Additional attributes of an item. For example validation and widget parameters
// *
// * @return
// */
// public val attributes: Meta?
//
// /**
// * An index field by which this node is identified in case of same name siblings construct
// */
// public val indexKey: String
//
// /**
// * Compute and cache the default [Meta] value described by this descriptor
// */
// public val defaultValue: Meta?
//
// public companion object {
// public const val DEFAULT_INDEX_KEY: String = "@index"
// }
//}
//
//
///**
// * The builder for [ItemDescriptor]
// */
//@DFBuilder
//public sealed class ItemDescriptorBuilder(final override val config: MutableMeta) : Configurable, ItemDescriptor {
//
// /**
// * True if same name siblings with this name are allowed
// */
// override var multiple: Boolean by config.boolean(false)
//
// /**
// * The item description text
// */
// override var info: String? by config.string()
//
// /**
// * True if the item is required
// */
// abstract override var required: Boolean
//
//
// /**
// * Additional attributes of an item. For example validation and widget parameters
// *
// * @return
// */
// override var attributes: MutableMeta? by config.node()
//
// /**
// * An index field by which this node is identified in case of same name siblings construct
// */
// override var indexKey: String by config.string(DEFAULT_INDEX_KEY)
//
// public abstract fun build(): ItemDescriptor
//
// override fun toMeta(): Meta = config
//
// public companion object {
// public const val DEFAULT_INDEX_KEY: String = "@index"
// }
//}
//
///**
// * Configure attributes of the descriptor, creating an attributes node if needed.
// */
//public inline fun ItemDescriptorBuilder.attributes(block: MutableMeta.() -> Unit) {
// (attributes ?: MutableMeta().also { this.attributes = it }).apply(block)
//}
//
///**
// * Check if given item suits the descriptor
// */
//public fun ItemDescriptor.validateItem(item: MetaItem?): Boolean {
// if (item == null) return !required
// return when (this) {
// is ValueDescriptor -> isAllowedValue(item.value ?: return false)
// is NodeDescriptor -> items.all { (key, d) ->
// d.validateItem(item.node[key])
// }
// }
//}
//
///**
// * Get a descriptor item associated with given name or null if item for given name not provided
// */
//public operator fun ItemDescriptor.get(name: Name): ItemDescriptor? {
// if (name.isEmpty()) return this
// return when (this) {
// is ValueDescriptor -> null // empty name already checked
// is NodeDescriptor -> items[name.firstOrNull()!!.toString()]?.get(name.cutFirst())
// }
//}
//
//public operator fun ItemDescriptor.get(name: String): ItemDescriptor? = get(name.toName())
//

View File

@ -8,13 +8,34 @@ import space.kscience.dataforge.names.*
import space.kscience.dataforge.values.Value
import space.kscience.dataforge.values.ValueType
/**
* The restriction on Meta node content
*/
public enum class MetaNodeRequirements {
/**
* no restrictions
*/
NONE,
/**
* The node itself must exist
*/
EXIST,
/**
* Value must be present
*/
HAS_VALUE
}
/**
* The descriptor for a meta
* @param info description text
* @param children child descriptors for this node
* @param multiple True if same name siblings with this name are allowed
* @param required True if the item is required
* @param type list of allowed types for [Meta.value], null if all values are allowed. If the type is [ValueType.NULL], no value is allowed for this node.
* @param required The requirements for node content
* @param valueTypes list of allowed types for [Meta.value], null if all values are allowed.
* Empty list means that no value should be present in this node.
* @param indexKey An index field by which this node is identified in case of same name siblings construct
* @param defaultValue the default [Meta.value] for the node
* @param attributes additional attributes of this descriptor. For example validation and widget parameters
@ -24,8 +45,8 @@ public data class MetaDescriptor(
public val info: String? = null,
public val children: Map<String, MetaDescriptor> = emptyMap(),
public val multiple: Boolean = false,
public val required: Boolean = false,
public val type: List<ValueType>? = null,
public val required: MetaNodeRequirements = MetaNodeRequirements.NONE,
public val valueTypes: List<ValueType>? = null,
public val indexKey: String = Meta.INDEX_KEY,
public val defaultValue: Value? = null,
public val attributes: Meta = Meta.EMPTY,
@ -58,9 +79,22 @@ public val MetaDescriptor.defaultNode: Meta
}
}
public fun MetaDescriptor.validate(value: Value?): Boolean = if (value == null) {
required != MetaNodeRequirements.HAS_VALUE
} else {
(valueTypes == null || value.type in valueTypes) && (allowedValues?.let { value in it } ?: true)
}
/**
* Check if given item suits the descriptor
*/
public fun MetaDescriptor.validate(item: Meta?): Boolean = (item != null || !required) &&
allowedValues?.let { item?.value in it } ?: true &&
children.all { (key, childDescriptor) -> childDescriptor.validate(item?.get(key)) }
public fun MetaDescriptor.validate(item: Meta?): Boolean {
if (item == null) return required == MetaNodeRequirements.NONE
if (!validate(item.value)) return false
children.forEach { (key, childDescriptor) ->
if (!childDescriptor.validate(item[key])) return false
}
return true
}

View File

@ -1,9 +1,6 @@
package space.kscience.dataforge.meta.descriptors
import space.kscience.dataforge.meta.Meta
import space.kscience.dataforge.meta.MutableMeta
import space.kscience.dataforge.meta.get
import space.kscience.dataforge.meta.set
import space.kscience.dataforge.meta.*
import space.kscience.dataforge.names.Name
import space.kscience.dataforge.names.cutFirst
import space.kscience.dataforge.names.first
@ -11,21 +8,13 @@ import space.kscience.dataforge.names.length
import space.kscience.dataforge.values.Value
import space.kscience.dataforge.values.ValueType
import space.kscience.dataforge.values.asValue
import kotlin.collections.List
import kotlin.collections.MutableMap
import kotlin.collections.emptyList
import kotlin.collections.getOrPut
import kotlin.collections.hashMapOf
import kotlin.collections.listOf
import kotlin.collections.map
import kotlin.collections.mapValues
import kotlin.collections.set
public class MetaDescriptorBuilder {
public class MetaDescriptorBuilder internal constructor() {
public var info: String? = null
public var children: MutableMap<String, MetaDescriptorBuilder> = hashMapOf()
public var multiple: Boolean = false
public var required: Boolean = false
public var required: MetaNodeRequirements = MetaNodeRequirements.NONE
public var type: List<ValueType>? = null
@ -42,6 +31,22 @@ public class MetaDescriptorBuilder {
public var attributes: MutableMeta = MutableMeta()
public inline fun attributes(block: MutableMeta.() -> Unit) {
attributes.apply(block)
}
public fun item(name: Name, descriptor: MetaDescriptor) {
when (name.length) {
0 -> {}
1 -> {
children[name.first().body] = descriptor.toBuilder()
}
else -> {
children.getOrPut(name.first().body) { MetaDescriptorBuilder() }.item(name.cutFirst(), descriptor)
}
}
}
public fun item(name: Name, block: MetaDescriptorBuilder.() -> Unit) {
when (name.length) {
0 -> apply(block)
@ -71,7 +76,7 @@ public class MetaDescriptorBuilder {
children = children.mapValues { it.value.build() },
multiple = multiple,
required = required,
type = type,
valueTypes = type,
indexKey = indexKey,
defaultValue = default,
attributes = attributes
@ -127,10 +132,27 @@ public inline fun <reified E : Enum<E>> MetaDescriptorBuilder.enum(
key: Name,
default: E?,
crossinline modifier: MetaDescriptorBuilder.() -> Unit = {},
): Unit = value(key,ValueType.STRING) {
): Unit = value(key, ValueType.STRING) {
default?.let {
this.default = default.asValue()
}
allowedValues = enumValues<E>().map { it.asValue() }
modifier()
}
private fun MetaDescriptor.toBuilder(): MetaDescriptorBuilder = MetaDescriptorBuilder().apply {
info = this@toBuilder.info
children = this@toBuilder.children.mapValuesTo(LinkedHashMap()) { it.value.toBuilder() }
multiple = this@toBuilder.multiple
required = this@toBuilder.required
type = this@toBuilder.valueTypes
indexKey = this@toBuilder.indexKey
default = defaultValue
attributes = this@toBuilder.attributes.toMutableMeta()
}
/**
* Make a deep copy of this descriptor applying given transformation [block]
*/
public fun MetaDescriptor.copy(block: MetaDescriptorBuilder.() -> Unit = {}): MetaDescriptor =
toBuilder().apply(block).build()

View File

@ -1,222 +0,0 @@
//package space.kscience.dataforge.meta.descriptors
//
//import space.kscience.dataforge.meta.*
//import space.kscience.dataforge.misc.DFBuilder
//import space.kscience.dataforge.names.*
//
//
///**
// * A [Meta] that is constructed from [NodeDescriptor]
// */
//private class DescriptorMeta(val descriptor: NodeDescriptor) : AbstractMeta() {
// override val items: Map<NameToken, MetaItem>
// get() = buildMap {
// descriptor.items.forEach { (token, descriptorItem) ->
// val item = descriptorItem.defaultValue
// if (item != null) {
// put(NameToken(token), item)
// }
// }
// }
//}
//
//
///**
// * Descriptor for meta node. Could contain additional information for viewing
// * and editing.
// *
// * @author Alexander Nozik
// */
//@DFBuilder
//public sealed interface NodeDescriptor : ItemDescriptor {
// /**
// * True if the node is required
// *
// * @return
// */
// override val required: Boolean
//
// /**
// * The default for this node. Null if there is no default.
// *
// * @return
// */
// public val default: Meta?
//
// /**
// * The map of children item descriptors (both nodes and values)
// */
// public val items: Map<String, ItemDescriptor>
//
// /**
// * The map of children node descriptors
// */
// public val nodes: Map<String, NodeDescriptor>
//
// /**
// * The list of children value descriptors
// */
// public val values: Map<String, ValueDescriptor>
//
// /**
// * Generate a laminate representing default item set generated by this descriptor
// */
// public val defaultMeta: Laminate
//
// public companion object {
//
// internal val ITEM_KEY: Name = "item".asName()
// internal val IS_NODE_KEY: Name = "@isNode".asName()
//
// //TODO infer descriptor from spec
// }
//}
//
//
//@DFBuilder
//public class NodeDescriptorBuilder(config: MutableMeta = MutableMeta()) : ItemDescriptorBuilder(config), NodeDescriptor {
// init {
// config[IS_NODE_KEY] = true
// }
//
// /**
// * True if the node is required
// *
// * @return
// */
// override var required: Boolean by config.boolean { default == null }
//
// /**
// * The default for this node. Null if there is no default.
// *
// * @return
// */
// override var default: MutableMeta? by config.node()
//
// /**
// * The map of children item descriptors (both nodes and values)
// */
// override val items: Map<String, ItemDescriptor>
// get() = config.getIndexed(ITEM_KEY).entries.associate { (name, item) ->
// if (name == null) error("Child item index should not be null")
// val node = item.node ?: error("Node descriptor must be a node")
// if (node[IS_NODE_KEY].boolean == true) {
// name to NodeDescriptorBuilder(node as MutableMeta)
// } else {
// name to ValueDescriptorBuilder(node as MutableMeta)
// }
// }
//
// /**
// * The map of children node descriptors
// */
// @Suppress("UNCHECKED_CAST")
// override val nodes: Map<String, NodeDescriptor>
// get() = config.getIndexed(ITEM_KEY).entries.filter {
// it.value.node[IS_NODE_KEY].boolean == true
// }.associate { (name, item) ->
// if (name == null) error("Child node index should not be null")
// val node = item.node ?: error("Node descriptor must be a node")
// name to NodeDescriptorBuilder(node as MutableMeta)
// }
//
// /**
// * The list of children value descriptors
// */
// override val values: Map<String, ValueDescriptor>
// get() = config.getIndexed(ITEM_KEY).entries.filter {
// it.value.node[IS_NODE_KEY].boolean != true
// }.associate { (name, item) ->
// if (name == null) error("Child value index should not be null")
// val node = item.node ?: error("Node descriptor must be a node")
// name to ValueDescriptorBuilder(node as MutableMeta)
// }
//
// private fun buildNode(name: Name): NodeDescriptorBuilder {
// return when (name.length) {
// 0 -> this
// 1 -> {
// val token = NameToken(ITEM_KEY.toString(), name.toString())
// val config: MutableMeta = config[token].node ?: MutableMeta().also {
// it[IS_NODE_KEY] = true
// config[token] = it
// }
// NodeDescriptorBuilder(config)
// }
// else -> buildNode(name.firstOrNull()?.asName()!!).buildNode(name.cutFirst())
// }
// }
//
// /**
// * Define a child item descriptor for this node
// */
// private fun newItem(key: String, descriptor: ItemDescriptor) {
// if (items.keys.contains(key)) error("The key $key already exists in descriptor")
// val token = ITEM_KEY.withIndex(key)
// config[token] = descriptor.toMeta()
// }
//
// public fun item(name: Name, descriptor: ItemDescriptor) {
// buildNode(name.cutLast()).newItem(name.lastOrNull().toString(), descriptor)
// }
//
// public fun item(name: String, descriptor: ItemDescriptor) {
// item(name.toName(), descriptor)
// }
//
// /**
// * Create and configure a child node descriptor
// */
// public fun node(name: Name, block: NodeDescriptorBuilder.() -> Unit) {
// item(name, NodeDescriptorBuilder().apply(block))
// }
//
// public fun node(name: String, block: NodeDescriptorBuilder.() -> Unit) {
// node(name.toName(), block)
// }
//
// /**
// * Create and configure child value descriptor
// */
// public fun value(name: Name, block: ValueDescriptorBuilder.() -> Unit) {
// require(name.length >= 1) { "Name length for value descriptor must be non-empty" }
// item(name, ValueDescriptorBuilder().apply(block))
// }
//
// public fun value(name: String, block: ValueDescriptorBuilder.() -> Unit) {
// value(name.toName(), block)
// }
//
// /**
// * Generate a laminate representing default item set generated by this descriptor
// */
// override val defaultMeta: Laminate by lazy { Laminate(default, DescriptorMeta(this)) }
//
// /**
// * Build a default [MetaItemNode] from this node descriptor
// */
// override val defaultValue: MetaItem get() = MetaItemNode(defaultMeta)
//
// override fun build(): NodeDescriptor = NodeDescriptorBuilder(config.copy())
//
// public companion object {
//
// internal val ITEM_KEY: Name = "item".asName()
// internal val IS_NODE_KEY: Name = "@isNode".asName()
//
// //TODO infer descriptor from spec
// }
//}
//
//public inline fun NodeDescriptor(block: NodeDescriptorBuilder.() -> Unit): NodeDescriptor =
// NodeDescriptorBuilder().apply(block)
//
///**
// * Merge two node descriptors into one using first one as primary
// */
//public operator fun NodeDescriptor.plus(other: NodeDescriptor): NodeDescriptor {
// return NodeDescriptorBuilder().apply {
// config.update(other.toMeta())
// config.update(this@plus.toMeta())
// }
//}

View File

@ -1,139 +0,0 @@
//package space.kscience.dataforge.meta.descriptors
//
//import space.kscience.dataforge.meta.*
//import space.kscience.dataforge.misc.DFBuilder
//import space.kscience.dataforge.values.*
//
//
///**
// * A descriptor for meta value
// *
// * Descriptor can have non-atomic path. It is resolved when descriptor is added to the node
// *
// * @author Alexander Nozik
// */
//@DFBuilder
//public sealed interface ValueDescriptor : ItemDescriptor {
//
// /**
// * True if the value is required
// *
// * @return
// */
// override val required: Boolean
//
// /**
// * The default for this value. Null if there is no default.
// *
// * @return
// */
// public val default: Value?
//
//
// /**
// * A list of allowed ValueTypes. Empty if any value type allowed
// *
// * @return
// */
// public val type: List<ValueType>?
//
// /**
// * Check if given value is allowed for here. The type should be allowed and
// * if it is value should be within allowed values
// *
// * @param value
// * @return
// */
// public fun isAllowedValue(value: Value): Boolean =
// (type?.let { it.contains(ValueType.STRING) || it.contains(value.type) } ?: true)
// && (allowedValues.isEmpty() || allowedValues.contains(value))
//
// /**
// * A list of allowed values with descriptions. If empty than any value is
// * allowed.
// *
// * @return
// */
// public val allowedValues: List<Value>
//}
//
///**
// * A builder fir [ValueDescriptor]
// */
//@DFBuilder
//public class ValueDescriptorBuilder(
// config: MutableMeta = MutableMeta()
//) : ItemDescriptorBuilder(config), ValueDescriptor {
//
// /**
// * True if the value is required
// *
// * @return
// */
// override var required: Boolean by config.boolean { default == null }
//
// /**
// * The default for this value. Null if there is no default.
// *
// * @return
// */
// override var default: Value? by config.value()
//
// public fun default(v: Any) {
// this.default = Value.of(v)
// }
//
// /**
// * A list of allowed ValueTypes. Empty if any value type allowed
// *
// * @return
// */
// override var type: List<ValueType>? by config.listValue { ValueType.valueOf(it.string) }
//
// public fun type(vararg t: ValueType) {
// this.type = listOf(*t)
// }
//
// /**
// * Check if given value is allowed for here. The type should be allowed and
// * if it is value should be within allowed values
// *
// * @param value
// * @return
// */
// override fun isAllowedValue(value: Value): Boolean {
// return (type?.let { it.contains(ValueType.STRING) || it.contains(value.type) } ?: true)
// && (allowedValues.isEmpty() || allowedValues.contains(value))
// }
//
// /**
// * A list of allowed values with descriptions. If empty than any value is
// * allowed.
// *
// * @return
// */
// override var allowedValues: List<Value> by config.item().convert(
// reader = {
// val value = it.value
// when {
// value?.list != null -> value.list
// type?.let { type -> type.size == 1 && type[0] === ValueType.BOOLEAN } ?: false -> listOf(True, False)
// else -> emptyList()
// }
// },
// writer = {
// MetaItemValue(it.asValue())
// }
// )
//
// /**
// * Allow given list of value and forbid others
// */
// public fun allow(vararg v: Any) {
// this.allowedValues = v.map { Value.of(it) }
// }
//
// override val defaultValue: MetaItem? get() = default?.asMetaItem()
//
// override fun build(): ValueDescriptor = ValueDescriptorBuilder(config.copy())
//}

View File

@ -48,6 +48,11 @@ public class Name(public val tokens: List<NameToken>) {
public val EMPTY: Name = Name(emptyList())
/**
* Convert a list of strings to a [Name] interpreting all arguments as token bodies without indices
*/
public fun of(vararg strings: String): Name = Name(strings.map { NameToken(it) })
/**
* Convert a [String] to name parsing it and extracting name tokens and index syntax.
* This operation is rather heavy so it should be used with care in high performance code.

View File

@ -62,7 +62,7 @@ class SpecificationTest {
fun testChildUpdate() {
val config = MutableMeta()
val child = config.getOrCreate("child")
child.update(TestScheme) {
child.updateWith(TestScheme) {
a = 22
b = "test"
}