oxidecomputer/typify

spuriously duplicated types may be generated

ahl opened this issue · 0 comments

ahl commented

Consider this case (roughly) from the checked in github.json data:

    "issue_comment$deleted": {
      "$schema": "http://json-schema.org/draft-07/schema",
      "type": "object",
      "required": ["action", "issue", "comment", "repository", "sender"],
      "properties": {
        "action": { "type": "string", "enum": ["deleted"] },
        "issue": {
          "description": "The [issue](https://docs.github.com/en/rest/reference/issues) the comment belongs to.",
          "allOf": [
            { "$ref": "#/definitions/issue" },
            {
              "type": "object",
              "required": ["labels", "state", "locked", "assignee"],
              "properties": {
                "assignee": {
                  "oneOf": [
                    { "$ref": "#/definitions/user" },
                    { "type": "null" }
                  ]
                },
...

In particular note issue and it's assignee property. In #/definitions/issue (think of it as the base class), assignee is defined like this:

        "assignee": {
          "oneOf": [{ "$ref": "#/definitions/user" }, { "type": "null" }]
        },

So... the same. We would expect the merge logic to try to merge these two (identical) oneOfs and come up with that same, identical oneOf. That's sometimes not what happens, in particular if the #/definitions/user type is sufficiently complex. In that case we get a type generated named IssueCommentDeletedIssueAssignee that is identical to the User type.

Here is a schema that reproduces the issue:

{
  "definitions": {
    "issue": {
      "type": "object",
      "required": [
        "assignee"
      ],
      "properties": {
        "assignee": {
          "oneOf": [
            {
              "$ref": "#/definitions/user"
            },
            {
              "type": "null"
            }
          ]
        }
      }
    },
    "issue_comment$deleted": {
      "type": "object",
      "required": [
        "issue"
      ],
      "properties": {
        "issue": {
          "allOf": [
            {
              "$ref": "#/definitions/issue"
            },
            {
              "type": "object",
              "required": [
                "assignee"
              ],
              "properties": {
                "assignee": {
                  "oneOf": [
                    {
                      "$ref": "#/definitions/user"
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              }
            }
          ]
        }
      }
    },
    "user": {
      "$schema": "http://json-schema.org/draft-07/schema",
      "type": "object",
      "properties": {
        "email": {
          "type": [
            "string",
            "null"
          ]
        }
      }
    }
  }
}

Note that if we made #/definitions/user/properties/email/type into a simple type (e.g. "string") rather than a type array, we get the expected result.