Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Properties order #7

Open
mfulton26 opened this issue Apr 6, 2018 · 14 comments
Open

Properties order #7

mfulton26 opened this issue Apr 6, 2018 · 14 comments

Comments

@mfulton26
Copy link

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.

@handrews
Copy link
Contributor

Reopening, as this was not being tracked anywhere else.

@handrews handrews reopened this Jan 16, 2020
@karenetheridge
Copy link
Member

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.)

@ssbarnea
Copy link

ssbarnea commented Apr 2, 2022

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.

@awwright
Copy link
Member

@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?

@ssbarnea
Copy link

@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?

@gregsdennis
Copy link
Member

@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.

@mfulton26
Copy link
Author

mfulton26 commented Jun 17, 2022

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.

@ssbarnea
Copy link

ssbarnea commented Jun 17, 2022

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": [".*"]

@handrews
Copy link
Contributor

@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).

@mfulton26
Copy link
Author

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)

@gregsdennis
Copy link
Member

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.

@alexburner
Copy link

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.

@gregsdennis
Copy link
Member

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-, so x-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.

@alexburner
Copy link

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants