Order of properties arbitrary?
Sajjon opened this issue · 6 comments
The order of the properties
is a bit strange. The order between the spec and the generated model is not the same. This is a bit problematic since we sometimes want to specify orders of the properties in our generated Swift files and the only way o
template.stencil
{% for p in spec.properties %}
var {{ p.name }}: {{ p.type }} { get }
{% endfor %}
"properties": {
"a": {"type": "integer"}
}
is trivial of course and results in:
var a: Int { get }
When we add a new property b
below/after a
, we expect b
to be declared after a
in the generated Swift file:
"properties": {
"a": {"type": "integer"},
"b": {"type": "integer"}
}
However, it results in the unexpected:
var b: Int { get }
var a: Int { get }
Hmm... "So maybe the order is reversed?" I thought, so continuing with a third property c
:
"properties": {
"a": {"type": "integer"},
"b": {"type": "integer"},
"c": {"type": "integer"}
}
Now it gets really interesting, this results in the super unexpected Swift code:
var b: Int { get }
var a: Int { get }
var c: Int { get }
"So what if the order is completely random?" I thought, so I cleared the contents of the file and ran ModelGen
like ten times. Same result, same order every time.
So what if we change a property, from type integer
to string
, what happens?
"properties": {
"a": {"type": "integer"},
"b": {"type": "string"},
"c": {"type": "integer"}
}
The order did not change, still the unexpected and unwanted b, a, c
:
var b: String { get }
var a: Int { get }
var c: Int { get }
Adding a forth, d
:
"properties": {
"a": {"type": "integer"},
"b": {"type": "string"},
"c": {"type": "integer"},
"d": {"type": "integer"},
}
Results in the unexpected:
var b: String { get }
var a: Int { get }
var d: Int { get }
var c: Int { get }
Adding a fifth e
:
"properties": {
"a": {"type": "integer"},
"b": {"type": "string"},
"c": {"type": "integer"},
"d": {"type": "integer"},
"e": {"type": "integer"}
}
Results in:
protocol RemoveThisModelTestingOnly {
var b: String { get }
var e: Int { get }
var a: Int { get }
var d: Int { get }
var c: Int { get }
}
So the weird thing is that the same order seems to be occurring every time, but the order itself is completely arbitrary? At least I can see a pattern:
a
b, a
b, a, c
b, a, d, c
b, e, a, d, c
What is the cause of this? Because in JsonParser+Context
it seems to be keeping the order in the method dicToArray
:
private func dicToArray() throws {
guard let items = json["properties"] as? JSON else {
throw JsonParserError.missingProperties
}
var properties = [JSON]()
for (key, value) in items {
guard let value = value as? JSON else {
throw JsonParserError.missingProperties
}
var nValue = value
nValue["name"] = key
properties.append(nValue)
}
json["properties"] = properties
}
The functions func mapProperties()
and func prepareProperties(_ items: [JSON], language: Language)
also seem to be keeping the order?
I struggled with this for a while because I wanted to render in the same order. If I remember that correct the problem is that the language will never preserve the order of a dictionary, I really wanted to do that but to be honest it is not something that we need because the order doesn't really matter while using it. So I just stopped working on that.
I think the order is missed when going to the stencil template.
@hebertialmeida maybe you could try to point me in the right direction? I posted some code snippets above and in those, I just saw arrays (var properties = [JSON]()
), where in the code are the properties stored in a dictionary?
What we could do at least is to replace the arbitrary ordering to be alphabetically ordered. In the function private func prepareContextFor(_ language: Language) throws {
we see this assignment:
json["properties"] = elements
where elements
is an array [JSON]
so we could sort that on the property name
, then the ordering is at least a bit logical.
What do you think, should work?
First thing is that the properties
inside the template.stencil
is a dictionary when swift reads that file seems that it is not preserving the order.
One place that may work ordering is dicToArray
, because is where I convert the dictionary parsed from template to an array.
File: JsonParser+Context.swift
private func dicToArray() throws {
@hebertialmeida cool! It has been some time since I used ModelGen, but it is very cool indeed! I might revisit it.
Btw are you aware that you almost managed to follow up EXACTLY one year after :D :D missed it by a day :P
Yeah, sorry about that, I use that on my project but sorting wasn't a problem, but since I upgrade to new swift probably dictionaries have changed it's behaviour and somehow was a mess...