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

Add missing support for `dependencies` in `getSchema` #19

Closed benjdlambert closed 1 year ago

benjdlambert commented 1 year ago

Hey :wave:

I wonder if theres a different way to do this, but it looks like that I'm unable to get the schema for something that is defined in dependencies.

Say I have a schema that looks like the following:

const parsed = new Draft07({
  title: "Fill in some steps",
  required: [
    "name"
  ],
  properties: {
    name: {
      title: "Name",
      type: "string",
      description: "Unique name of the component"
    },
    generation: {
      type: "string",
      title: "Generation Method",
      enum: [
        "Hide Custom Field",
        "Display Custom Field"
      ],
      default: "Hide Custom Field"
    }
  },
  dependencies: {
    generation: {
      oneOf: [
        {
          properties: {
            generation: {
              const: "Hide Custom Field"
            }
          }
        },
        {
          required: [
            "customField"
          ],
          properties: {
            generation: {
              const: "Display Custom Field"
            },
            customField: {
              title: "Custom Field",
              type: "string"
            }
          }
        }
      ]
    }
  }
})

And then if I do parsed.getSchema('#/customField', { generation: 'Display Custom Field' }) I get Could not find a valid schema for property '#/customField' within object where as it should be part of the json schema for validation. Is there something I'm missing here or a way to get back the schema { type: string } for this bit in the schema?

Thanks!

sagold commented 1 year ago

Hi!

I will need to investigate this. Your example looks quite tricky.

sagold commented 1 year ago

short update: dependencies is currently only part of validation and not interpreted in other helper functions. Will need to add this to the general step-resolver as is done with anyOf, oneOf etc.

sagold commented 1 year ago

Hi Ben,

with version v6.1.0 support for dependencies has been added to getTemplate and getSchema. For your above example the following will work out of the box:

getSchema('#/customField', { generation: 'Display Custom Field', customField: "with-value" });
// { type: "string", title: "Custom Field" }

https://github.com/sagold/json-schema-library/blob/master/test/unit/issues/issue19.getSchema.dependencies.test.ts#L56

to retrieve the schema without passing a value for customField you need to change the oneOf resolution behaviour like so:

import { Draft07, resolveOneOfFuzzy } from "json-schema-library";
const core = new Draft07(schema);
core.resolveOneOf = function resolveOneOf(data, schema: JSONSchema, pointer: JSONPointer) {
    return resolveOneOfFuzzy(this, data, schema, pointer);
};

core.getSchema('#/customField', { generation: 'Display Custom Field' });
// { type: "string", title: "Custom Field" }

https://github.com/sagold/json-schema-library/blob/master/test/unit/issues/issue19.getSchema.dependencies.test.ts#L69

Per default, oneOf-options have to be strictly validated with the input value. In this case, all oneOf are invalid and return an error. The resolver resolveOneOfFuzzy instead will decide on a specific oneOf-schema and return this.

In my experience, working with a user interface supporting oneOf selection, you know exactly, which oneOf schema should be selected based on the input data. In your case, this is a selection based on a value for generation. In this case and using the resolveOneOfFuzzy you can add a property oneOfProperty which will use this property and its value to select a oneOf entry:

"dependencies": {
    "generation": {
      "oneOfProperty": "generation",
      "oneOf": [
        ...
      ]
   }
}

https://github.com/sagold/json-schema-library/blob/master/test/unit/issues/issue19.getSchema.dependencies.test.ts#L29

I do hope this helps and explains why oneOf resolution requires a little help here. Right now, replacing the resolveOneOf resolver requires a complete custom Core or the workaround above. I will rewrite the Core api next to support simpler configuration of such things.

With this, I close the issue. Feel free to ask or reopen this issue if it is not working.

Cheers.

benjdlambert commented 1 year ago

Nice! Thank you so much! Will give this a try out! :tada: