Json meta format fix

This commit is contained in:
Alexander Nozik 2019-03-19 10:57:41 +03:00
parent 9fd89a5b60
commit ce0e5d4f24
3 changed files with 85 additions and 102 deletions

View File

@ -3,6 +3,7 @@ package hep.dataforge.meta.io
import hep.dataforge.meta.Meta
import hep.dataforge.meta.MetaItem
import hep.dataforge.names.NameToken
import hep.dataforge.names.toName
import hep.dataforge.values.*
import kotlinx.io.core.Input
import kotlinx.io.core.Output
@ -22,10 +23,10 @@ object JsonMetaFormat : MetaFormat {
val str = input.readText()
val json = Json.plain.parseJson(str)
if(json is JsonObject) {
if (json is JsonObject) {
return json.toMeta()
} else {
TODO("non-object root")
TODO("Non-object root not supported")
}
}
}
@ -51,33 +52,46 @@ fun Meta.toJson(): JsonObject {
}
fun JsonElement.toMetaItem() = when (this) {
is JsonPrimitive -> MetaItem.ValueItem<JsonMeta>(this.toValue())
is JsonObject -> MetaItem.NodeItem(this.toMeta())
is JsonArray -> {
if (this.all { it is JsonPrimitive }) {
val value = ListValue(this.map { (it as JsonPrimitive).toValue() })
MetaItem.ValueItem<JsonMeta>(value)
} else {
TODO("mixed nodes json")
}
}
}
fun JsonObject.toMeta() = JsonMeta(this)
private fun JsonPrimitive.toValue(): Value {
class JsonMeta(val json: JsonObject) : Meta {
private fun JsonPrimitive.toValue(): Value {
return when (this) {
JsonNull -> Null
else -> this.content.parseValue() // Optimize number and boolean parsing
}
}
class JsonMeta(val json: JsonObject) : Meta {
override val items: Map<NameToken, MetaItem<out Meta>> by lazy {
json.mapKeys { NameToken(it.key) }.mapValues { entry ->
entry.value.toMetaItem()
}
private operator fun MutableMap<String, MetaItem<JsonMeta>>.set(key: String, value: JsonElement) = when (value) {
is JsonPrimitive -> this[key] = MetaItem.ValueItem(value.toValue())
is JsonObject -> this[key] = MetaItem.NodeItem(value.toMeta())
is JsonArray -> {
when {
value.all { it is JsonPrimitive } -> {
val listValue = ListValue(
value.map {
//We already checked that all values are primitives
(it as JsonPrimitive).toValue()
}
)
this[key] = MetaItem.ValueItem(listValue)
}
else -> value.forEachIndexed { index, jsonElement ->
when (jsonElement) {
is JsonObject -> this["$key[$index]"] = MetaItem.NodeItem(JsonMeta(jsonElement))
is JsonPrimitive -> this["$key[$index]"] = MetaItem.ValueItem(jsonElement.toValue())
is JsonArray -> TODO("Nested arrays not supported")
}
}
}
}
}
override val items: Map<NameToken, MetaItem<JsonMeta>> by lazy {
val map = HashMap<String, MetaItem<JsonMeta>>()
json.forEach { (key, value) -> map[key] = value }
map.mapKeys { it.key.toName().first()!! }
}
}

View File

@ -21,10 +21,8 @@
*/
package hep.dataforge.descriptors
import hep.dataforge.Named
import hep.dataforge.meta.*
import hep.dataforge.names.Name
import java.util.*
import hep.dataforge.names.toName
/**
* Descriptor for meta node. Could contain additional information for viewing
@ -32,7 +30,14 @@ import java.util.*
*
* @author Alexander Nozik
*/
open class NodeDescriptor(val meta: Meta) : MetaRepr {
class NodeDescriptor(override val config: Config) : Specification {
/**
* The name of this node
*
* @return
*/
var name: String by string { error("Anonymous descriptors are not allowed") }
/**
* True if multiple children with this nodes name are allowed. Anonymous
@ -40,104 +45,48 @@ open class NodeDescriptor(val meta: Meta) : MetaRepr {
*
* @return
*/
val multiple: Boolean by meta.boolean(false)
var multiple: Boolean by boolean(false)
/**
* True if the node is required
*
* @return
*/
val required: Boolean by meta.boolean(false)
var required: Boolean by boolean(false)
/**
* The node description
*
* @return
*/
open val info: String by meta.string("")
var info: String? by string()
/**
* A list of tags for this node. Tags used to customize node usage
*
* @return
*/
val tags: List<String> by customValue(def = emptyList()) { it.list.map { it.string } }
/**
* The name of this node
*
* @return
*/
override val name: String by stringValue(def = meta.name)
var tags: List<String> by value().map { value ->
value?.list?.map { it.string } ?: emptyList()
}
/**
* The list of value descriptors
*
* @return
*/
fun valueDescriptors(): Map<String, ValueDescriptor> {
val map = HashMap<String, ValueDescriptor>()
if (meta.hasMeta("value")) {
for (valueNode in meta.getMetaList("value")) {
val vd = ValueDescriptor(valueNode)
map[vd.name] = vd
}
}
return map
}
/**
* The child node descriptor for given name. Name syntax is supported.
*
* @param name
* @return
*/
fun getNodeDescriptor(name: String): NodeDescriptor? {
return getNodeDescriptor(Name.of(name))
}
fun getNodeDescriptor(name: Name): NodeDescriptor? {
return if (name.length == 1) {
childrenDescriptors()[name.unescaped]
} else {
getNodeDescriptor(name.cutLast())?.getNodeDescriptor(name.last)
}
}
/**
* The value descriptor for given value name. Name syntax is supported.
*
* @param name
* @return
*/
fun getValueDescriptor(name: String): ValueDescriptor? {
return getValueDescriptor(Name.of(name))
}
fun getValueDescriptor(name: Name): ValueDescriptor? {
return if (name.length == 1) {
valueDescriptors()[name.unescaped]
} else {
getNodeDescriptor(name.cutLast())?.getValueDescriptor(name.last)
}
val values: Map<String, ValueDescriptor>
get() = config.getAll("value".toName()).entries.associate { (name, node) ->
name to ValueDescriptor.wrap(node.node ?: error("Value descriptor must be a node"))
}
/**
* The map of children node descriptors
*
* @return
*/
fun childrenDescriptors(): Map<String, NodeDescriptor> {
val map = HashMap<String, NodeDescriptor>()
if (meta.hasMeta("node")) {
for (node in meta.getMetaList("node")) {
val nd = NodeDescriptor(node)
map[nd.name] = nd
}
}
return map
val nodes: Map<String, NodeDescriptor>
get() = config.getAll("node".toName()).entries.associate { (name, node) ->
name to NodeDescriptor.wrap(node.node ?: error("Node descriptor must be a node"))
}
/**
* Check if this node has default
*
@ -173,15 +122,14 @@ open class NodeDescriptor(val meta: Meta) : MetaRepr {
*/
val key: String by stringValue(def = "")
override fun toMeta(): Meta {
return meta
}
fun builder(): DescriptorBuilder = DescriptorBuilder(this.name, Configuration(this.meta))
//override val descriptor: NodeDescriptor = empty("descriptor")
companion object {
companion object : SpecificationCompanion<NodeDescriptor> {
override fun wrap(config: Config): NodeDescriptor = NodeDescriptor(config)
fun empty(nodeName: String): NodeDescriptor {
return NodeDescriptor(Meta.buildEmpty(nodeName))

View File

@ -0,0 +1,21 @@
package hep.dataforge.meta
fun Meta.toDynamic(): dynamic {
fun MetaItem<*>.toDynamic(): dynamic = when (this) {
is MetaItem.ValueItem -> this.value.value.asDynamic()
is MetaItem.NodeItem -> this.node.toDynamic()
}
val res = js("{}")
this.items.entries.groupBy { it.key.body }.forEach { (key, value) ->
val list = value.map { it.value }
res[key] = when (list.size) {
1 -> list.first().toDynamic()
else -> list.map { it.toDynamic() }
}
}
return res
}