Schema "AnyOf" generated as "anything"
remigailard80 opened this issue · comments
I generate a schema of this type,
export type ViewTypeReducerType =
AdvertisementOverviewViewType.AsObject
| ButtonTextViewType.AsObject
| FleaMarketOverviewViewType.AsObject
| EventOverviewViewType.AsObject
| GeneralBusinessOverviewViewType.AsObject
| GeneralOverviewViewType.AsObject
| GeneralProgressviewViewType.AsObject
| GeneralWatchOverviewViewType.AsObject
| ImageBannerViewType.AsObject
| NoticeOverviewViewType.AsObject
| PopupOverviewViewType.AsObject
| QuestionViewType.AsObject
| RegionCheckInViewType.AsObject
and generated stuff was
"ViewTypeReducerType": {
"anyOf": [
{
"type": "object",
"required": [
"type"
],
.....
, the anyOf
of objects.
and generated result on storybook was,
is there any method to resolve anyof
schema correctly?
Hey @remigailard80, will have a look at that, too! I don't think we have anyOf
in the addon yet.
Do you use the Controls
-addon, too? How do you handle the anyOf
for that, out of curiosity? 🤔
After some first testing, anyOf
should generally work, we have one case here:
https://www.kickstartds.com/storybook/?path=/story/base-section--inhaltsboxen
Could you post a slightly bigger excerpt of the anyOf
you're using? The example above looks like this in our code:
"content": {
"type": "array",
"items": {
"anyOf": [
{
"$ref": "http://frontend.ruhmesmeile.com/content/organisms/quotes-slider.schema.json"
},
{
"$ref": "http://frontend.ruhmesmeile.com/base/atoms/link-button.schema.json"
},
...
]
}
},
And those $ref
s get inlined by json-schema-ref-parser
before being put into the viewer.
I think I found the problem,
In the anyOf elements,
{
"$ref": "#/definitions/QuestionViewType.AsObject"
},
was the problem. If I delete that element from the anyOf
array, it parsed correctly as
anyOf [object, object, object , ... ]
Hey @remigailard80, will have a look at that, too! I don't think we have anyOf in the addon yet.
Do you use the Controls-addon, too? How do you handle the anyOf for that, out of curiosity? 🤔
using Controls-addon
.
I think I found the problem, In the anyOf elements,
{ "$ref": "#/definitions/QuestionViewType.AsObject" },
was the problem. If I delete that element from the
anyOf
array, it parsed correctly as
anyOf [object, object, object , ... ]
That's really interesting. Because it hints at the problem, I think! Because I don't know how those inline $ref
s are handled actually. Have you tried just removing all $ref
s by running json-schema-ref-parser
over it? 🤔 That should eliminate the problem entirely!
About controls-addon
: How do you handle the anyOf
there? I guess it's just a JSON field in the controls, right?
I use json-schema-ref-parser
and remove almost all of $ref
but,
{
"QuestionViewDataType": {
"$ref": "#/definitions/QuestionViewType.Data.AsObject"
},
"QuestionViewType.Data.AsObject": {
"type": "object",
"properties": {
"question": {
"$ref": "#/definitions/QuestionViewType.Question.AsObject"
}
},
"additionalProperties": false
},
"QuestionViewType.Question.AsObject": {
"type": "object",
"properties": {
"id": {
"type": "number"
},
"content": {
"type": "string"
},
"kind": {
"type": "number",
"enum": [
0,
1,
2,
3
]
},
"negativeButtonText": {
"type": "string"
},
"positiveButtonText": {
"type": "string"
},
"androidTargetUri": {
"type": "string"
},
"iosTargetUri": {
"type": "string"
},
"questions": {
"$ref": "#/definitions/QuestionViewType.Question.AsObject"
}
},
"required": [
"id",
"content",
"kind",
"negativeButtonText",
"positiveButtonText",
"androidTargetUri",
"iosTargetUri"
],
"additionalProperties": false
},
"QuestionViewType.KindType": {
"type": "number",
"enum": [
0,
1,
2,
3
]
}
}
}
because of this schema's circular ref, I added circular: "ignore"
option.
this is my schema generator for json-schema-ref-parser
const $RefParser = require('@apidevtools/json-schema-ref-parser');
const schema = require('./schema.json');
// safely handles circular references
JSON.safeStringify = (obj, indent = 2) => {
let cache = []; // circular references
const retVal = JSON.stringify(
obj,
(key, value) => {
return typeof value === "object" && value !== null
? cache.includes(value)
? value // Duplicate reference found, discard key
: cache.push(value) && value // Store value in our collection
: value
},
indent
);
cache = null;
return retVal;
};
$RefParser.dereference(schema, {
continueOnError: true,
resolve: {
external: true
},
dereference: {
circular: "ignore"
}
}).then(res => console.log(JSON.safeStringify(res)))
that's the reason why there remains $ref
, as i think.
About controls-addon: How do you handle the anyOf there? I guess it's just a JSON field in the controls, right?
right.
Could you keep those definitions
in the file? (e.g. #/definitions/QuestionViewType.Data.AsObject
)
Or did you just cut them manually, to make the snippet shorter? 🤔
Maybe it would just work, if you'd have those inline $ref
s only?
Alternatively you could replace those remaining $ref
s manually, in an additional processing pass. I know we're using https://github.com/epoberezkin/json-schema-traverse in some places to do similar stuff.
You could traverse the whole schema, before putting it into the addon, and just watch for the $ref
and replace it manually!
Edit: I think if it really is recursive, and needs to be displayed as such, it could get challenging!
Uploaded snippet is part of my schema(too long), so i cut them manually, which caused problem.
Maybe it would just work, if you'd have those inline $refs only?
is this meaning it is enough to work if there's inline $refs only
? Because I'm not good at English, so I may have misunderstood that phrase.
If I understood correctly, that cause some issue on storybook like,
the question
field should [object] that linked to QuestionViewType.Question.AsObject
, but appears anything
.
As you suggested, I think �I should use json-schema-traverse
to achieve my purpose.
You could give it a try, yeah! Let me know if it works!
And maybe the following snippet could help you:
const addExplicitAnyOfs = (schemaJson: JSONSchema7, schemaAnyOfs: JSONSchema7[]) => {
traverse(schemaJson, {
cb: (schema, pointer, rootSchema) => {
if (schema.items && schema.items.anyOf) {
const componentPath = rootSchema.$id.split('/');
const componentType = path.basename(rootSchema.$id).split('.')[0];
const componentName = uppercamelcase(componentType);
schema.items.anyOf = schema.items.anyOf.map((anyOf: JSONSchema7) => {
if (anyOf.$ref)
return anyOf;
const schemaName = `http://frontend.ruhmesmeile.com/${componentPath[3]}/${componentPath[4]}/${componentType}/${pointer.split('/').pop()}-${anyOf.title.replace(componentName, '').toLowerCase()}.interface.json`;
schemaAnyOfs.push({
$id: schemaName,
$schema: "http://json-schema.org/draft-07/schema#",
...anyOf,
definitions: schemaJson.definitions
});
return { $ref: schemaName };
});
}
}
});
}
It's not really doing what you need, but I think you could just modify it. This snippet takes all our anyOf
s, and makes $ref
s out of them (e.g. { type: 'object', 'properties': { 'size': {...} } }
gets turned into '$ref': 'sizeObject.schema.json'), I think you can use a similar approach to replace your recursive
$ref`s.
About the inline $ref
s, forget that. I don't think that would really help or actually work!
I'll try. thanks!