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

Add support for 'then/else' paths #1909

Conversation

nmaier95
Copy link
Contributor

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

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
@sdirix
Copy link
Member

sdirix commented Apr 6, 2022

Thanks for the PR. We'll have a look soon!

@coveralls
Copy link

coveralls commented Apr 6, 2022

Coverage Status

Coverage remained the same at 84.29% when pulling 8dd4852 on nmaier95:feature/support-conditional-schemas-inside-anyof-oneof-allof into 1410b58 on eclipsesource:master.

Copy link
Member

@sdirix sdirix left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @nmaier95!

Thanks a lot for the PR, it makes a lot of sense to me!

Note that we also support skipping oneOf/allOf/anyOf within the UI Schema scopes, see here. Would you be interested in something similar for the if/then/else parts? If yes, would you be willing to also contribute this?

@sdirix
Copy link
Member

sdirix commented Apr 7, 2022

Can you also add an example to the examples so this use case can be immediately tried?

@nmaier95
Copy link
Contributor Author

nmaier95 commented Apr 8, 2022

Hi @sdirix,

thank you for your feedback! I'll add an example.

Furthermore I'll have a look at the support of skipping the if/then/else part inside the scope of an ui-schema element.

@CLAassistant
Copy link

CLAassistant commented Apr 17, 2022

CLA assistant check
All committers have signed the CLA.

Copy link
Member

@sdirix sdirix left a 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.

Comment on lines 139 to 141
schema?.oneOf ?? [],
schema?.allOf ?? [],
schema?.anyOf ?? []
Copy link
Member

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?

Copy link
Contributor Author

@nmaier95 nmaier95 May 5, 2022

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.

Copy link
Member

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.

Copy link
Member

@sdirix sdirix left a 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.

Comment on lines 60 to 62
.replace(/anyOf\/[\d]\/((then|else)\/)?/g, '')
.replace(/allOf\/[\d]\/((then|else)\/)?/g, '')
.replace(/oneOf\/[\d]\/((then|else)\/)?/g, '');
Copy link
Member

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?

Suggested change
.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, '');

Comment on lines 139 to 141
schema?.oneOf ?? [],
schema?.allOf ?? [],
schema?.anyOf ?? []
Copy link
Member

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.

curSchema = resolveSchema(item, validPathSegments.slice(i).map(encode).join('/'));
if (curSchema) {
break;
}
if (!curSchema) {
Copy link
Member

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

Comment on lines 149 to 158
const conditionalSchemas = [].concat(
item.then ?? [],
item.else ?? [],
);
for (const condiItem of conditionalSchemas) {
curSchema = resolveSchema(condiItem, schemaPath);
if (curSchema) {
break;
}
}
Copy link
Member

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.

item.else ?? [],
);
for (const condiItem of conditionalSchemas) {
curSchema = resolveSchema(condiItem, schemaPath);
Copy link
Member

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.

@sdirix
Copy link
Member

sdirix commented May 11, 2022

@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.

@nmaier95
Copy link
Contributor Author

@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.

Copy link
Member

@AlexandraBuzila AlexandraBuzila left a 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 => {
Copy link
Member

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 😄

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops ;)

Copy link
Member

@AlexandraBuzila AlexandraBuzila left a 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!

@sdirix sdirix merged commit 11de281 into eclipsesource:master May 12, 2022
@sdirix sdirix changed the title Add support for conditional schema compositions Add support for 'then/else' paths May 12, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Control path resolution fails for "dynamically" added properties via conditional schema compositions
5 participants