json-schema-vocabularies
json-schema-vocabularies copied to clipboard
Properties order
UI generation tools would benefit, I think, from having a way to specify the order of properties.
For simple cases, perhaps properties
could be optionally defined as an array of objects where at a minimum each object has a name
property:
"properties": [
{
"name": "foo",
"type": "string"
},
{
"name": "bar",
"type": "boolean"
}
]
Alternatively a new keyword could be introduced, propertiesOrder
:
"properties": {
"bar": { "type": "boolean" },
"foo": { "type": "string" }
},
"propertiesOrder": ["foo", "bar"]
This keyword could also support patterns:
"properties": {
"bar": { "type": "boolean" },
"foo": { "type": "string" },
"num": { "type": "number" }
},
"propertiesOrder": [".*", "foo", "bar"]
Any properties not mentioned in a propertiesOrder
array (and are not matched by any patterns if supported) would go after any ordered properties and would not have a deterministic order.
Reopening, as this was not being tracked anywhere else.
Correct me if I'm wrong, but since the schema is defined with additionalProperties: true
, you can just add this to your schema today and interpret it any way you like in your application -- much like examples
, description
and $comment
are purely annotative and are ignored during evaluation. Do all annotative keys need to be in the spec?
(Personally, I would do {"properties":{"foo":{..., "sortOrder":0},"bar":{..., "sortOrder":1},...}}
and the sort function would look at the sortOrder
integer.)
Only slightly related to the current subject, but can someone recommend a tool, preferably js or python that can be used to sort schema definition files? As they grow fast and they are edited by numerous people I find quite hard to keep them in a relative normalized way.
A JSON sorted would be really welcomed here, especially if it can be configured to sort some properties on top of others, like $id
, title
, description
.
So far I found a prettier plugin that does basic sorting at https://www.npmjs.com/package/prettier-plugin-sort-json -- sadly title and description end-up at the weird positions.
@ssbarnea It's typical these days for properties to be listed by insert order (including in JSON.stringify), maybe just recreate the object in your preferred sort order. Does that make sense?
@awwright The idea is to declare the sort-order at schema level, so validators, editors, reformatters could make use of it.
I kinda like the simplicity of "propertiesOrder": ["title", "$comment", ".*", "foo", "bar"]
, especially if we can declare the fact that this property is inheritable by each child as I would not want to relist it in lots of places.
If inheriting from parent is not possible we should at least allow to configure implicit value at document/schema level, for the same reasons (to avoid repetition).
Does anyone know some ordering that could not be achieved with the proposed format? Or if they know another format which would make easier to be consumed by those that would implement it?
@ssbarnea are you looking for the schema to validate that the properties are in the right order? That's not something that can be guaranteed, especially interoperably. The parsers in some languages aren't even deterministic in property order from reading the same file multiple times.
Secondly, we don't have an idea of keyword inheritence in the way you're describing (flowing down from the parent). However, subschemas can be extracted into a $def
and references in mulitple places.
In addition to or in lieu of a "propertiesOrder"
array, supporting an array of tuples for "properties"
might be nice so that for simple schemas there's less repeating of property names (similar to the Map constructor parameters in JavaScript):
"properties": [
["bar", { "type": "boolean" }],
["foo", { "type": "string" }]
],
A "propertiesOrder"
could still be introduced for specifying order for properties not defined directly in the schema but that may get merged into it when conditional schemas are resolved, etc.
A "properties"
array might suffice on its on though. e.g. The following schema snippet defines a total ordering for the properties baz
, bar
, and foo
whether baz
is present or not;
"properties": [
["bar", { "type": "boolean" }],
["foo", { "type": "string" }]
],
"if": { /* condition schema */ },
"then": {
"properties": [
["baz", { "type": "number" }],
"bar",
"foo"
]
}
A UI derived from the schema wouldn't show a baz
property at all unless the condition schema evaluated to true.
The full list of properties could even not be required to be specified in the conditional schema. As long as one other property is defined for a point of reference then the insertion point can be determined.
"properties": [
["bar", { "type": "boolean" }],
["foo", { "type": "string" }]
],
"if": { /* condition schema */ },
"then": {
"properties": [
["baz", { "type": "number" }],
"bar",
// foo is omitted
// baz clearly goes before bar
]
}
There would need to be clear rules defined for merged schemas as to what order takes precedence over order defined elsewhere, etc. That goes for a "properties"
array solution as well as a "propertiesOrder"
array solution. A "properties"
array helps reduce repeating property names and might be easier to work with.
I am personally against over-complicating that feature, shortly I find the simple list of strings being more than enough to enable tools to determine how to sort. Property type should not be among criterias, if someone wants to determine prefered sorting using this they can do it while listing the fields names.
Keep in mind that this extension works like "prefered-sort-order", it does not act as a validation. Schema can still be valid regardless the order of the keys. The main use case is for editors and I suspect especially for those using YAML files.
Here is two practical examples:
package.json
"propertiesOrder": [
"name",
"version",
".*",
"scripts"
]
ansible tasks
That example is bit simplified as in reality I do expect that list to grow much longer, this being likely one of the most complex sorting logics.
"propertiesOrder": [
"name", # always first!
".*",
"action",
"args",
"with_.*",
"loop",
"loop_.*",
"when",
"tags", # tags are usually last
"block", # ensure nothing goes after block as it often causes indentation bugs
]
simple alphabetical sorting
If someone wants to just use alphabetical sorting:
"propertiesOrder": [".*"]
@ssbarnea
Keep in mind that this extension works like "prefered-sort-order", it does not act as a validation.
Yes, a propertiesOrder
keyword would be an annotation, not an assertion, since the JSON data model does not include property order.
An advantage here is that in the newer drafts, the default behavior for unrecognized keywords is to treat the as simple annotations, so you wouldn't need to write custom code to support it (if you can use an implementation that collects annotations and implements the new default behavior, anyway).
@mfulton26 we try to avoid changing existing keywords without very good reason. On reason that has been considered "very good" is to split keywords with two different syntaxes for different behaviors, so changing properties
in the way you propose would go in the opposite direction. If you want a new syntax with a new behavior, that should be a new keyword.
In particular, since an assertion cannot validate field order due to the limitations of JSON's data model, a keyword that tries to impart ordering while also having assertion behavior (properties
isn't an assertion on its own, but ANDs the assertion results of its subschemas) would be extra-confusing. 2020-12 has two separate vocabularies for format
to keep the annotation and assertion behavior separate (but format
is not a good precedent for anything - the two vocabulary approach is a patch on a difficult historical keyword, not a best practice for new keywords).
thank you for the explanation @handrews; very helpful!
my ideas around a "properties"
array came to mind when considering @ssbarnea's question, "Does anyone … know another format which would make easier to be consumed by those that would implement it?"
I appreciate all the points raised here and I too find a "propertiesOrder"
annotation simple and straight forward (although maybe a little verbose but that isn't inherently a bad thing)
It sounds like you intend this to be in support of tooling, such as a linter. If that's the case, I suggest that this be prepared in a separate vocabulary, not added to the core or validation spec.
It sounds like you intend this to be in support of tooling, such as a linter. If that's the case, I suggest that this be prepared in a separate vocabulary, not added to the core or validation spec.
This is a tricky question, touching on the overall philosophy/purpose of JSON Schema..
I do think that describing properties order would fit into the current declared goal:
Welcome to JSON Schema, a declarative language that allows you to annotate and validate JSON documents.
Not the validation aspect, but the annotation aspect, as @handrews comments above:
Yes, a propertiesOrder keyword would be an annotation, not an assertion, since the JSON data model does not include property order.
We're currently using react-jsonschema-form
to define tooling integration config, and would appreciate the ability to define propertiesOrder
— our schemas are defined deep in the stack, and by the time they reach the frontend they've usually lost their original sort, which makes for some non-intuitive form field ordering.
We'll likely start using propertiesOrder
to solve this now, but it would be nice to have it officially in the spec, instead of merely being an ignored additional prop.
It sounds like you intend this to be in support of tooling, such as a linter. If that's the case, I suggest that this be prepared in a separate vocabulary, not added to the core or validation spec.
This is a tricky question, touching on the overall philosophy/purpose of JSON Schema..
Defining this in a separate vocabulary does follow the philosophy/purpose of JSON Schema.
- With 2020-12, annotation-only keywords don't need to be defined in a vocabulary; unknown keywords have their values automatically collected as annotations. Just add the keyword to the schema.
- With the upcoming stable release, we're moving to a "no unknown keywords" model but allowing any keywords that start with
x-
, sox-propertyNames
is something that you can just add and it will be collected as an annotation.
Then just use the annotation in your form generation.
Of course, it'll likely need to be react-jsonschema-form
or whatever library you're using to generate forms that ultimately needs to support the keyword.
With the upcoming stable release, we're moving to a "no unknown keywords" model but allowing any keywords that start with x-, so x-propertyNames is something that you can just add and it will be collected as an annotation.
Oo this is good info, thanks! We'll use the x-
for any customizations
With the upcoming stable release, we're moving to a "no unknown keywords" model but allowing any keywords that start with x-, so x-propertyNames is something that you can just add and it will be collected as an annotation.
And HTTP standard has moved away from x- prefix: https://datatracker.ietf.org/doc/html/rfc6648
For anyone who's interested in such a solution, I've found https://pypi.org/project/jschon-sort/ which sorts yaml/json according to a json schema.