-
Notifications
You must be signed in to change notification settings - Fork 373
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
Add support for 'then/else' paths #1909
Add support for 'then/else' paths #1909
Conversation
If properties of a schema were added conditionally inside an anyof|oneof|allof list their paths were not resolved correctly. For reference see second example in: https://json-schema.org/understanding-json-schema/reference/conditionals.html#if-then-else
Thanks for the PR. We'll have a look soon! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you also add an example to the |
Hi @sdirix, thank you for your feedback! I'll add an example. Furthermore I'll have a look at the support of skipping the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general this looks very good and I would like to merge this soon. However there is one detail I would like to have explained.
packages/core/src/util/resolvers.ts
Outdated
schema?.oneOf ?? [], | ||
schema?.allOf ?? [], | ||
schema?.anyOf ?? [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you explain the use cases where this is necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll try to explain this in english. I hope it is comprehensible.
The resultSchema
variable already holds the first resolved path entry. Which mostyl is properties
.
If we take for example, the example given in the corresponding test-file resolvers.test.ts
there I defined an anyOf
in the root of the schema. The problem was that this code would now search further inside properties
for the scopes defined inside anyOf
- where it would not find those. That is why we need to also add the root level compositions here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It feels weird to me that we single out the case that the anyOf/allOf/oneOf
is attached to the start where we want to resolve from. The problem you mention can happen at any point of the resolving, so we only solve this for the one special case here.
…onditional-schemas-inside-anyof-oneof-allof
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at the code in more detail I think we could do better by generalizing the code a bit. Also the resolving could easier handle all cases by transforming it to a depth-first search.
packages/core/src/util/path.ts
Outdated
.replace(/anyOf\/[\d]\/((then|else)\/)?/g, '') | ||
.replace(/allOf\/[\d]\/((then|else)\/)?/g, '') | ||
.replace(/oneOf\/[\d]\/((then|else)\/)?/g, ''); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this just be another line? e.g. .replace(/(then|else)\//g, '')
?
I don't see why we should restrict ourselves purely to the case that the then
or else
is within a combinator. We also want to remove them when they are outside of them.
Actually we could then just simplify to this, right?
.replace(/anyOf\/[\d]\/((then|else)\/)?/g, '') | |
.replace(/allOf\/[\d]\/((then|else)\/)?/g, '') | |
.replace(/oneOf\/[\d]\/((then|else)\/)?/g, ''); | |
.replace(/(anyOf|allOf|oneOf)\/[\d]\//g, '') | |
.replace(/(then|else)\//g, ''); |
packages/core/src/util/resolvers.ts
Outdated
schema?.oneOf ?? [], | ||
schema?.allOf ?? [], | ||
schema?.anyOf ?? [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It feels weird to me that we single out the case that the anyOf/allOf/oneOf
is attached to the start where we want to resolve from. The problem you mention can happen at any point of the resolving, so we only solve this for the one special case here.
packages/core/src/util/resolvers.ts
Outdated
curSchema = resolveSchema(item, validPathSegments.slice(i).map(encode).join('/')); | ||
if (curSchema) { | ||
break; | ||
} | ||
if (!curSchema) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This condition must be true, otherwise we would not be executed. see the break
above
packages/core/src/util/resolvers.ts
Outdated
const conditionalSchemas = [].concat( | ||
item.then ?? [], | ||
item.else ?? [], | ||
); | ||
for (const condiItem of conditionalSchemas) { | ||
curSchema = resolveSchema(condiItem, schemaPath); | ||
if (curSchema) { | ||
break; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This only works if the then/else
is directly below a combinator. If they are more nested, this will not resolve.
packages/core/src/util/resolvers.ts
Outdated
item.else ?? [], | ||
); | ||
for (const condiItem of conditionalSchemas) { | ||
curSchema = resolveSchema(condiItem, schemaPath); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By handing over the whole schemaPath
instead of the current segment list this will only ever be correct for the special root case.
@nmaier95 I have a fix for my requests ready. Please allow edits by maintainers so I can add them to this PR. Otherwise I'll have to close this one and reopen a new PR. |
It should be allowed now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the changes, they look good to me.
There's only one small comment in one of the tests that should be addressed.
@@ -25,7 +25,7 @@ | |||
import { resolveSchema } from '../../src/util/resolvers'; | |||
import test from 'ava'; | |||
|
|||
test('resolveSchema - resolves schema with any ', t => { | |||
test.only('resolveSchema - resolves schema with any ', t => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
only
should be removed from here 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oops ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, changes look good now!
If properties of a schema were added conditionally inside
an anyof|oneof|allof list their paths were not resolved
correctly.
For reference see second example in:
https://json-schema.org/understanding-json-schema/reference/conditionals.html#if-then-else
resolves #1907