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

Duplicate (nested) discriminator union values not allowed #1750

Open
maxboone opened this issue Aug 14, 2023 · 0 comments
Open

Duplicate (nested) discriminator union values not allowed #1750

maxboone opened this issue Aug 14, 2023 · 0 comments

Comments

@maxboone
Copy link

maxboone commented Aug 14, 2023

Take, for example, a collection of pets:

type RedCat = { color: "red" };
type AshCat = { color: "ash" };

/**
 * @discriminator color
 */
type Cat = AshCat | RedCat;

/**
 * @discriminator animal
 */
type Pet = (
    ({ animal: "cat" } & Cat)
    | ({ animal: "dog" })
);

This yields an error that there are "Duplicate discriminator values: cat", which makes sense, as there are now two elements that match the "animal" tag. Not passing a discriminator will yield a (fairly flat) JSON Schema, but I like using the if-else statements for better error messages and more readability of the schema.

I'd expect something like the following to be possible to generate, by extending the current logic:

{
  "$ref": "#/definitions/Pet",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "definitions": {
    "Pet": {
      "allOf": [
        {
          "if": {
            "properties": {
              "animal": {
                "const": "cat",
                "type": "string"
              }
            }
          },
          "then": {
            "$ref": "#/definitions/Cat"
          }
        },
        {
          "if": {
            "properties": {
              "animal": {
                "const": "dog",
                "type": "string"
              }
            }
          },
          "then": {
            "$ref": "#/definitions/Dog"
          }
        }
      ],
      "properties": {
        "animal": {
          "type": "string",
          "enum": ["dog", "cat"]
        }
      },
      "required": ["animal"],
      "type": "object"
    },
    "Dog": {
      "type": "object"
    },
    "Cat": {
      "allOf": [
        {
          "if": {
            "properties": {
              "color": {
                "const": "red",
                "type": "string"
              }
            }
          },
          "then": {
            "$ref": "#/definitions/RedCat"
          }
        },
        {
          "if": {
            "properties": {
              "color": {
                "const": "ash",
                "type": "string"
              }
            }
          },
          "then": {
            "$ref": "#/definitions/AshCat"
          }
        }
      ],
      "properties": {
        "color": {
          "type": "string",
          "enum": ["ash", "red"]
        }
      },
      "required": ["color"],
      "type": "object"
    },
    "RedCat": {
      "type": "object"
    },
    "AshCat": {
      "type": "object"
    }
  }
}

I would, in this case, add some recursive logic that also applies the if-then constants to the leafs so that they can disable additional properties for better type checking.

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

1 participant