Cyclical dependency in oneOf causes generation to fatal
sey opened this issue · 1 comments
sey commented
I am trying to define a JSON schema for expressions (similar to what Mongo does).
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"$ref": "#/definitions/expression"
},
"definitions": {
"fieldExpression": {
"type": "object",
"propertyNames": { "type": "string" },
"patternProperties": {
"^.*$": {
"type": "object",
"properties": {
"$eq": { "type": ["boolean", "number", "string", "null"] },
"$ne": { "type": ["boolean", "number", "string", "null"] },
"$gt": { "type": ["number", "string"] },
"$gte": { "type": ["number", "string"] },
"$lt": { "type": ["number", "string"] },
"$lte": { "type": ["number", "string"] }
},
"minProperties": 1,
"additionalProperties": false
}
},
"additionalProperties": false
},
"logicalOperator": {
"type": "object",
"oneOf": [
{
"properties": {
"$and": {
"type": "array",
"items": { "$ref": "#/definitions/expression" },
"minItems": 1
}
},
"required": ["$and"],
"additionalProperties": false
},
{
"properties": {
"$or": {
"type": "array",
"items": { "$ref": "#/definitions/expression" },
"minItems": 1
}
},
"required": ["$or"],
"additionalProperties": false
},
{
"properties": {
"$not": { "$ref": "#/definitions/expression" }
},
"required": ["$not"],
"additionalProperties": false
}
]
},
"expression": {
"oneOf": [
{ "$ref": "#/definitions/fieldExpression" },
{ "$ref": "#/definitions/logicalOperator" }
]
}
}
}
It fails with
[
TypeError: Converting circular structure to JSON
--> starting at object with constructor 'Array'
| index 1 -> object with constructor 'Object'
| property 'oneOf' -> object with constructor 'Array'
| ...
| index 0 -> object with constructor 'Object'
--- property 'oneOf' closes the circle
at JSON.stringify (<anonymous>)
at generateRawType (/Users/florian/Developer/repositories/proximus/digital-kyc-onboarding-app/node_modules/json-schema-to-typescript/dist/src/generator.js:171:25)
This is due to logical operator being recursive.
Are you aware of a way to express the recursive aspect in a different way supported by this package?
alexmojaki commented
I think your schema is wrong. This:
"properties": {
"$ref": "#/definitions/expression"
},
translates to:
"properties": {
"oneOf": [
{ "$ref": "#/definitions/fieldExpression" },
{ "$ref": "#/definitions/logicalOperator" }
]
},
which I think doesn't make sense. I tried three online JSON schema validators and they agreed. So I think this is a +1 for #48.
This works:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"title": "Expression",
"oneOf": [
{
"$ref": "#/definitions/fieldExpression"
},
{
"$ref": "#/definitions/logicalOperator"
}
],
"definitions": {
"fieldExpression": {
"type": "object",
"propertyNames": {
"type": "string"
},
"patternProperties": {
"^.*$": {
"type": "object",
"properties": {
"$eq": {
"type": [
"boolean",
"number",
"string",
"null"
]
},
"$ne": {
"type": [
"boolean",
"number",
"string",
"null"
]
},
"$gt": {
"type": [
"number",
"string"
]
},
"$gte": {
"type": [
"number",
"string"
]
},
"$lt": {
"type": [
"number",
"string"
]
},
"$lte": {
"type": [
"number",
"string"
]
}
},
"minProperties": 1,
"additionalProperties": false
}
},
"additionalProperties": false
},
"logicalOperator": {
"type": "object",
"oneOf": [
{
"properties": {
"$and": {
"type": "array",
"items": {
"$ref": "#"
},
"minItems": 1
}
},
"required": [
"$and"
],
"additionalProperties": false
},
{
"properties": {
"$or": {
"type": "array",
"items": {
"$ref": "#"
},
"minItems": 1
}
},
"required": [
"$or"
],
"additionalProperties": false
},
{
"properties": {
"$not": {
"$ref": "#"
}
},
"required": [
"$not"
],
"additionalProperties": false
}
]
}
}
}
Output:
/* eslint-disable */
/**
* This file was automatically generated by json-schema-to-typescript.
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
* and run json-schema-to-typescript to regenerate this file.
*/
export type Expression = FieldExpression | LogicalOperator;
export type LogicalOperator =
| {
/**
* @minItems 1
*/
$and: [Expression, ...Expression[]];
}
| {
/**
* @minItems 1
*/
$or: [Expression, ...Expression[]];
}
| {
$not: Expression;
};
export interface FieldExpression {
/**
* This interface was referenced by `FieldExpression`'s JSON-Schema definition
* via the `patternProperty` "^.*$".
*/
[k: string]: {
$eq?: boolean | number | string | null;
$ne?: boolean | number | string | null;
$gt?: number | string;
$gte?: number | string;
$lt?: number | string;
$lte?: number | string;
};
}