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

Improve output for top level $ref #132

Open
dherges opened this issue Nov 16, 2017 · 16 comments
Open

Improve output for top level $ref #132

dherges opened this issue Nov 16, 2017 · 16 comments

Comments

@dherges
Copy link

dherges commented Nov 16, 2017

A $ref breaks when used on the root object

Example A

Non-working example:

{
 "$schema": "http:https://json-schema.org/draft-04/schema#",
 "type": "object",
 "$ref": "#/definitions/anatomic-location",
  "definitions": {
    "anatomic-location": {
      "description": "thing",
      "properties": {
        /* .. */
        "children": {
          "type": "array",
          "items": { "$ref": "#/definitions/anatomic-location" }
        },
      }
    }
  }
}

Error message will be:

Refs should have been resolved by the resolver!

It will log:

  title: 'AnatomicLocation',
  properties: 
   { id: { type: 'integer' } },
  '$ref': '#' }

I wonder where the $ref: '#' comes from?

Example B

Working but with duplicated interface

  "$schema": "http:https://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "$ref": "#/definitions/anatomic-location/properties"
  },
  "definitions": {
    "anatomic-location": {
      "description": "thing...",
       "properties": { /* .. */ }
     }
  }
}

Generated code is:

export interface AnatomicLocation {
  id?: number;
  children?: AnatomicLocation1[];
}

export interface AnatomicLocation1 {
  id: number;
  children?: AnatomicLocation1[];
}
@bcherny bcherny self-assigned this Nov 16, 2017
@bcherny
Copy link
Owner

bcherny commented Nov 16, 2017

Thanks for the reports @dherges.

@BigstickCarpet Is Example A kosher?

@bcherny
Copy link
Owner

bcherny commented Nov 16, 2017

@dherges Can you post the complete JSON-Schema for Example B? From what you gave it's not clear to me why the output is incorrect.

@dherges
Copy link
Author

dherges commented Nov 16, 2017

Hi @bcherny,

thanks for the response and your time! Here are the full repros.

Example A

{
  "title": "Example Schema",
  "definitions": {
    "person": {
      "type": "object",
      "properties": {
        "firstName": {
          "type": "string"
        },
        "children": {
          "type": "array",
          "items": { "$ref": "#/definitions/person" }
        }
      }
    }
  },
  "type": "object",
  "$ref": "#/definitions/person"
}

Error message:

$ node_modules/.bin/json2ts wound-ui/ui/foo.json 
error Refs should have been resolved by the resolver! { title: 'Example Schema',
  definitions: { person: { type: 'object', properties: [Object] } },
  type: 'object',
  required: [],
  additionalProperties: true,
  id: 'Foo',
  properties: 
   { firstName: { type: 'string' },
     children: { type: 'array', items: [Object] } },
  '$ref': '#' }

Example B

{
  "title": "Example Schema",
  "definitions": {
    "person": {
      "type": "object",
      "properties": {
        "firstName": {
          "type": "string"
        },
        "children": {
          "type": "array",
          "items": { "$ref": "#/definitions/person" }
        }
      }
    }
  },
  "type": "object",
  "properties": {
    "$ref": "#/definitions/person/properties"
  }
}
export interface ExampleSchema {
  firstName?: string;
  children?: Person[];
  [k: string]: any;
}
export interface Person {
  firstName?: string;
  children?: Person[];
  [k: string]: any;
}

I could live by that output as it's somewhat 'okay' due to duck typing in TypeScript world, but I wonder why two interfaces are being generated?!?

@dherges
Copy link
Author

dherges commented Nov 16, 2017

I found two working version by setting $ref: '.' and $ref: '#' in the properties.children.items:

{
  "type": "object",
  "properties": {
    "firstName": {
      "type": "string"
    },
    "children": {
      "type": "array",
      "items": { "$ref": "." }
   }
  }
}
export interface Bar {
  firstName?: string;
  children?: Bar[];
  [k: string]: any;
}

{
  "type": "object",
  "properties": {
    "firstName": {
      "type": "string"
    },
    "children": {
      "type": "array",
      "items": { "$ref": "#" }
   }
  }
}
export interface Bar {
  firstName?: string;
  children?: Bar[];
  [k: string]: any;
}

@JamesMessinger
Copy link

JamesMessinger commented Nov 17, 2017

@bcherny - Example A in @dherges' post isn't supported by json-schema-ref-parser. It's technically not a valid JSON Schema, since a JSON Reference object is only allowed to have a $ref property (any other property are ignored, per the spec).

{
  "$ref": "#/foo/bar",
  "name": "Foo"               // <--- not allowed
}

That said, json-schema-ref-parser supports JSON Reference objects with additional properties, even though that's not technically spec-compliant. I chose to support it because many people asked for it and had real-world situations where they relied on it. However, allowing a non-spec-compliant feature causes problems such as the one that @dherges is facing.

My recommendation is to go with something like Example B in @dherges' post. Even though it may not seem quite as elegant, it is spec-compliant.

@bcherny
Copy link
Owner

bcherny commented Nov 17, 2017

@BigstickCarpet As always, thanks for chiming in.

@dherges You heard it here, Example A is invalid. For example B, nicer output might be:

export type ExampleSchema = Person
export interface Person {
  firstName?: string;
  children?: Person[];
  [k: string]: any;
}

Is that what you had in mind?

@bcherny
Copy link
Owner

bcherny commented Nov 28, 2017

@dherges Can you chime in?

@dherges
Copy link
Author

dherges commented Nov 28, 2017

Yes, exactly!

@zoonman
Copy link

zoonman commented Mar 1, 2021

I have the same issue. Here is a schema
eksctl.json.zip

@k2on
Copy link

k2on commented Mar 27, 2021

Any update on this?

@ShivamJoker
Copy link

I am stil getting this error any workarounds?

@mmdk95
Copy link

mmdk95 commented Sep 12, 2022

As I ran into the same issue (and this is the top result in google), here is what you can do to prevent this error from occurring (not gonna join the debate on valid or invalid schema 😉 ).

As your$ref can most likely be replaced with an allOf, instead of doing something like this:

YAML JSON
$ref: "#/definitions/child"
definitions:
  child:
     description: Hello World
{
   "$ref": "#/definitions/child",
   "definitions": {
       "child": {
          "description": "Hello World",
       }  
   }
}

You can do this, and your types should generate

YAML JSON
allOf:
- $ref: "#/definitions/child"
definitions:
  child:
    description: Hello World
{
   "allOf": [
      { "$ref": "#/definitions/child" }
   ],
   "definitions": {
       "child": {
          "description": "Hello World",
       }  
   }
}

@zanona
Copy link

zanona commented Feb 11, 2023

Just listing an example being used in production, I hope that's ok.
https://turbo.build/schema.json

{
  "$schema": "http:https://json-schema.org/draft-07/schema#",
  "$ref": "#/definitions/Schema",
  "definitions": {
    "Schema": {
      "type": "object",
      "properties": {...}
    }
  }
}

@toteto
Copy link

toteto commented Oct 19, 2023

Facing the same issue for schema at: https://github.com/decentralized-identity/presentation-exchange/blob/main/schemas/v2.0.0/submission-requirement.json

submission-requirement.json
{
  "$schema": "http:https://json-schema.org/draft-07/schema#",
  "title": "Presentation Submission Requirement",
  "definitions": {
    "submission_requirement": {
      "type": "object",
      "oneOf": [
        {
          "properties": {
            "name": { "type": "string" },
            "purpose": { "type": "string" },
            "rule": {
              "type": "string",
              "enum": ["all", "pick"]
            },
            "count": { "type": "integer", "minimum": 1 },
            "min": { "type": "integer", "minimum": 0 },
            "max": { "type": "integer", "minimum": 0 },
            "from": { "type": "string" }
          },
          "required": ["rule", "from"],
          "additionalProperties": false
        },
        {
          "properties": {
            "name": { "type": "string" },
            "purpose": { "type": "string" },
            "rule": {
              "type": "string",
              "enum": ["all", "pick"]
            },
            "count": { "type": "integer", "minimum": 1 },
            "min": { "type": "integer", "minimum": 0 },
            "max": { "type": "integer", "minimum": 0 },
            "from_nested": {
              "type": "array",
              "minItems": 1,
              "items": {
                "$ref": "#/definitions/submission_requirement"
              }
            }
          },
          "required": ["rule", "from_nested"],
          "additionalProperties": false
        }
      ]
    }
  },
  "$ref": "#/definitions/submission_requirement"
}

Using the workaround from @mmdk95 for now

@ManAnRuck
Copy link

ManAnRuck commented Feb 12, 2024

i have the same problem with the openapi schema (3.1)
https://github.com/OAI/OpenAPI-Specification/blob/main/schemas/v3.1/schema.json

@mathematikoi
Copy link

i have the same problem with the openapi schema (3.1) https://github.com/OAI/OpenAPI-Specification/blob/main/schemas/v3.1/schema.json

same

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests