sagold / json-schema-library

Customizable and hackable json-validator and json-schema utilities for traversal, data generation and validation
MIT License
164 stars 19 forks source link

Template generation for arrays with `anyOf` clobbers valid default values using first schema's template #38

Closed snoozbuster closed 10 months ago

snoozbuster commented 1 year ago

Given the following schema listSchemaWithDefault:

{
  "type": "object",
  "properties": {
    "someList": {
      "type": "array",
      "items": { "anyOf": [{ "a": "number" }, { "b": "string" }, { "c": { "const": "foo" } }] },
      "minItems": 3,
      "default": [
        { "a": 1 },
        { "b": "schfifty-five" },
        { "c": "foo" }
      ]
    }
  }
}

calling new Draft07(listSchemaWithDefault).getTemplate() will return something to the effect of:

{
  "someList": [
    { "a": 1 },
    { "a": 0, "b": "schfifty-five" }
    { "a": 0, "c": "foo" }
  ]
}

(furthermore, as an additional and separate issue, these objects are permanently overwritten in the original schema object as an unavoidable side-effect.)

The expected behavior in this case would be to return the default value as-is, as each object is valid according to one of the schemas in anyOf. Additionally, if the middle schema in the anyOf was modified to { "required": ["b", "f"], "b": "string", "f": { "const": "bar" } }, I would expect that the middle object would be returned from getTemplate as { "b": "schfifty-five", "f": "bar" } (without modifying the original value).

My understanding is the getSchema function already has the ability to a piece of data to a specific schema that is present in an anyOf (as per the docs):

image

In this case, as I understand it, calling new Draft07(listSchemaWithDefault).getSchema('/someList/1', listSchemaWithDefault.properties.someList.default) would return the value { "b": "string" } as expected. Therefore, my belief is that the bug lies in getTemplateSchema - instead of always taking the first item, it should attempt to resolve the passed in data to the matching schema from the anyOf using the same technique as in getSchema.

sagold commented 1 year ago

Hi snoozbuster,

I agree. For the example above, we would expect

{
  "someList": [
    { "a": 1 },
    { "b": "schfifty-five" },
    { "c": "foo" }
  ]
}

The other issue you mention is, that the schema from new Draft07(listSchemaWithDefault).getSchema().properties.someList.default is modified and every item contains an a property?

I will look into it!

sagold commented 1 year ago

Testing this, this issue has been already fixed in the upcoming version 8, which can currently be installed using json-schema-library@8.0.0-rc6. I working towards a full v8 release in the next weeks. If you go for this package, be aware of the breaking changes:

References

sagold commented 1 year ago

json-schema-library@8.0.0 has been released to npm and includes a fix for this issue.