quicktype icon indicating copy to clipboard operation
quicktype copied to clipboard

Wrong enum name when using union with null

Open bdeneux opened this issue 2 years ago • 1 comments

I've an issue when trying to convert a JSON schema file to Typescript types. The JSON schema comes from a Rust models that has been converted to JSON Schema.

Given this schema : (I've simplified the schema for this exemple)

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "ConstructResponse",
  "description": "Represents the response of a [QueryMsg::Construct] query.",
  "type": "object",
  "required": [
    "format"
  ],
  "properties": {
    "format": {
      "description": "The format of the data.",
      "anyOf": [
        {
          "$ref": "#/definitions/DataFormat"
        },
        {
           "type": "null"
        }
      ]
    }
  },
  "additionalProperties": false,
  "definitions": {
    "DataFormat": {
      "title": "DataFormat",
      "description": [...],
      "oneOf": [
        {
          "title": "Turtle",
          "description": [...]
          "type": "string",
          "enum": [
            "turtle"
          ]
        },
        {
          "title": "RDF XML",
          "description": [...],
          "type": "string",
          "enum": [
            "rdf_xml"
          ]
        },
        {
          "title": "N-Triples",
          [...]
        },
        {
          "title": "N-Quads",
          [...]
        }
      ]
    }
  }
}

And running QuickType to convert this json schema in Typescript types,

quicktype -s schema schema.json -o test.ts --prefer-type

The conversion use the first enum case as the name of the enum, here the enum will be named Turtle instead of DataFormat.

/**
 * Represents the response of a [QueryMsg::Construct] query.
 */
export type Test = {
    format: Turtle | null;
}

export enum Turtle {
    NQuads = "n_quads",
    NTriples = "n_triples",
    RDFXML = "rdf_xml",
    Turtle = "turtle",
}
Expected result
/**
 * Represents the response of a [QueryMsg::Construct] query.
 */
export type Test = {
    format: DataFormat | null;
}

export enum DataFormat {
    NQuads = "n_quads",
    NTriples = "n_triples",
    RDFXML = "rdf_xml",
    Turtle = "turtle",
}

When I remove { "type": "null" } from the anyOf property of DataFormat, the enum is named correctly.

JSON without the `null` union
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "ConstructResponse",
  "description": "Represents the response of a [QueryMsg::Construct] query.",
  "type": "object",
  "required": [
    "format"
  ],
  "properties": {
    "format": {
      "description": "The format of the data.",
      "anyOf": [
        {
          "$ref": "#/definitions/DataFormat"
        }
      ]
    }
  },
  "additionalProperties": false,
  "definitions": {
    "DataFormat": {
      "title": "DataFormat",
      "description": [...],
      "oneOf": [
        {
          "title": "Turtle",
          "description": [...]
          "type": "string",
          "enum": [
            "turtle"
          ]
        },
        {
          "title": "RDF XML",
          "description": [...],
          "type": "string",
          "enum": [
            "rdf_xml"
          ]
        },
        {
          "title": "N-Triples",
          [...]
        },
        {
          "title": "N-Quads",
          [...]
        }
      ]
    }
  }
}

Give a good enum name but is not what I want because DataFormat is optional :

/**
 * Represents the response of a [QueryMsg::Construct] query.
 */
export type Test = {
    format: DataFormat;
}

export enum DataFormat {
    NQuads = "n_quads",
    NTriples = "n_triples",
    RDFXML = "rdf_xml",
    Turtle = "turtle",
}

This null type union has been added because format property can be null since this attribute is optional in rust.

I hope you can help me, I'm wondering if it's an issue in this library for this particular case or if it's the JSON Schema that has been malformed by the rust library.

bdeneux avatar Sep 19 '23 16:09 bdeneux

Hi @bdeneux, there looks to be 2 issues at play here:

  1. There does indeed seem to be a naming issue here with the Enum, which I will take a look at
  2. For an optional property on the format object, an easier representation would just be to omit the key from the required array - although the anyOf with null is also correct (and might make more sense coming from rust)

inferrinizzard avatar May 21 '24 14:05 inferrinizzard