JSON: retain original order of map entries?
I was trying to read a grammar.json file from tree-sitter: it looks like this
{
"name": "smithyql",
"rules": {
"source_file": {
"type": "SEQ",
"members": ...
},
"prelude": {
"type": "REPEAT1",
"content": {
"type": "SYMBOL",
"name": "use_clause"
}
},
...
Notably, the first rule is supposed to be the entrypoint to parsing a file. However, when I tried to model this as Smithy:
structure Grammar {
@required
name: String
@required
rules: Rules
}
map Rules {
key: TypeName
value: Document
}
and read it as JSON:
val grammar =
Json
.read[Grammar](
Blob(Files.readString(Paths.get("tree-sitter-smithyql/src/grammar.json")))
)
.toTry
.get
grammar.rules.toList.map(_._1).foreach(println)
Then source_file was actually last - in any case, the ordering is not preserved.
Is this something we should support, maybe with an optional meta trait that'd turn the map into a ListMap? Or should it be the default?
Tested on 0.18.27.
Yeah, an optional meta trait is gonna be the way to go, but this goes in with the question of abstracting over Map in the Schema GADT (the same way we've abstracted over collections via a tag to allow for IndexedSeq/Vector/etc). So I think this is a 0.19 concern.
As for the problem at hand, I think you can work around it by using the newly supported @jsonUnknown : if you know there's gonna be a source_file field, may as well model it in a structure and get the rest as an free-form map.
if you know there's gonna be a source_file field, may as well model it in a structure and get the rest as an free-form map.
I don't know that - the schema is supposed to work for any tree-sitter grammar out there. It just happens that source_file is the first rule (meaning the root) of my exact grammar.
Not sure if @jsonUnknown will give me the original ordering, I guess that depends on how Documents get decoded. I'll be back with info.
update: yeah @jsonUnknown gets placed on a shape targetting a Map[String, Document], so the result ends up with arbitrary ordering again. I guess the suggestion only applied with the assumption that source_file was known as a static entry.
How about using of java.util.LinkedHashMap that preserves ordering of inserts and has efficient resolution of key hash collisions that is not vulnerable under DoS attacks?
And, please, never use ListMap because its inserts and lookups have O(n) complexity.
there's no immutable variant, is there? :/
related: https://github.com/smithy-lang/smithy/issues/2572
@Baccata I don't think a meta trait is the way to go, actually.
Meta traits are all used for codegen, right? Whereas order of entries is more of an encoding concern, would need to work in Dynamic land, and thus would belong more in Alloy, imo.
Happy to use ju.LHM if we can cover it up with scala.collection.immutable.Map without copying 👍