bcherny / json-schema-to-typescript

Compile JSON Schema to TypeScript type declarations
https://bcherny.github.io/json-schema-to-typescript-browser/
MIT License
2.95k stars 392 forks source link

`RangeError` for circular references to `oneOf` containing definition with the `$ref` #547

Closed christianklotz closed 1 year ago

christianklotz commented 1 year ago

I have been trying to generate Typescript types from the Amazon State Language JSON Schema which leads to the following error:

RangeError: Maximum call stack size exceeded

As far as I can tell this is a circular reference where the referenced definition itself is a oneOf which in turn contains the definition with the $ref.

  "Not": {
    "$ref": "#/properties/States/additionalProperties/oneOf/4/allOf/2/properties/Choices/items/oneOf/18/properties/Not"
  },

Removing all unnecessary layers and definitions leaves the following schema.

Reduced schema

{
  "type": "object",
  "properties": {
    "States": {
      "type": "object",
      "properties": {
        "Choices": {
          "type": "array",
          "description": "An array of Choice Rules that determines which state the state machine transitions to next.",
          "minItems": 1,
          "items": {
            "type": "object",
            "properties": {
              "Not": {
                "oneOf": [
                  {
                    "type": "object",
                    "properties": {
                      "Not": {
                        "$ref": "#/properties/States/properties/Choices/items/properties/Not"
                      }
                    },
                    "required": [
                      "Not"
                    ]
                  }
                ]
              }
            },
            "required": [
              "Not"
            ]
          },
          "additionalItems": false
        }
      },
      "required": [
        "Choices"
      ]
    }
  },
  "required": [
    "States"
  ]
}

Reduced schema without oneOf in referenced type

The moment the referenced definition is an object, no longer a oneOf, the circular reference gets resolved correctly.

{
  "type": "object",
  "properties": {
    "States": {
      "type": "object",
      "properties": {
        "Choices": {
          "type": "array",
          "description": "An array of Choice Rules that determines which state the state machine transitions to next.",
          "minItems": 1,
          "items": {
            "type": "object",
            "properties": {
              "Not": {
                "type": "object",
                "properties": {
                  "Not": {
                    "$ref": "#/properties/States/properties/Choices/items/properties/Not"
                  }
                },
                "required": [
                  "Not"
                ]
              }
            },
            "required": [
              "Not"
            ]
          },
          "additionalItems": false
        }
      },
      "required": [
        "Choices"
      ]
    }
  },
  "required": [
    "States"
  ]
}

I'd be happy to take a look myself but would appreciate a few suggestions on where to look, possible routes.

christianklotz commented 1 year ago

I looked at the issues earlier but somehow missed #523 which looks very similar.

bcherny commented 1 year ago

Dup of #523

alexmojaki commented 1 year ago

I disagree with closing this as a duplicate:

  1. Per my comment on #523, it seems like that issue isn't an issue at all as the reported schema is invalid.
  2. The error is different: TypeError: Converting circular structure to JSON vs RangeError: Maximum call stack size exceeded.
  3. Closing this issue means that future readers are likely to only read the other issue and not this one and most likely get an incomplete picture.

Having said that, the minimal schema given here is confusing to think about. Unlike the other issue, this one passes validation, but it still seems invalid because I can't see how to construct a finite valid object according to the schema:

Screenshot from 2023-08-27 13-40-15