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

Smart Validator #58

Merged
merged 22 commits into from
Aug 2, 2024
Merged

Smart Validator #58

merged 22 commits into from
Aug 2, 2024

Conversation

mbasaglia
Copy link
Member

@mbasaglia mbasaglia commented Jul 9, 2024

Currently using https://ajv.js.org/ for schema validation. Depending on how things work we might want to switch to completely custom validation to ensure the errors are sensible

@mbasaglia
Copy link
Member Author

@b-wils

@mbasaglia
Copy link
Member Author

Ideally I'd like to tag all unknown properties as warnings, maybe with an option to turn them off.

@b-wils
Copy link
Contributor

b-wils commented Jul 9, 2024

Very cool, excited to look at this. Some related thoughts I had on validation-

  1. We could consider adding discriminators to the schema (https://ajv.js.org/json-schema.html#discriminator) to reduce oneOf error noise. The two big downsides are (a) they aren't part of the json schema spec, though they do have support in some tooling (b) they only work on string types, so we couldn't use them for layers.

  2. I likely have some use cases where we want unknown properties as errors. If we just want a list of unknown properties, we could probably create a strict version of the schema and then diff it with the non-strict version to get that list.

@mbasaglia
Copy link
Member Author

Ajv also allows you to perform custom validation, that could also be a possibility

@mbasaglia
Copy link
Member Author

OK so I managed to use AJV builtin functionality to perform validation based on ty. The discriminator stuff was too unflexible so I wrote a custom keyword that does it. Their documentation on the matter was rather lacking so it was quite tricky to figure out but now it works:

Screenshot_20240710_065403

},
{
keyword: "prop_oneof",
validate: custom_discriminator("a"),
Copy link
Contributor

Choose a reason for hiding this comment

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

What do you think of converting the schema to use if/then/else instead of oneOf for animated properties? That should improve those error messages and would not need any custom logic so would work with any validator.

One thing I'm not sure of is if that would impact the doc generation tools.

Copy link
Member Author

Choose a reason for hiding this comment

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

I think it would be harder to maintain, also from what I've heard if/else is not always well supported by tooling, there were some issues in the lottie-docs schema that used if/else more often

Copy link
Contributor

Choose a reason for hiding this comment

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

I think "if" would be easier to maintain as we currently repeat the animated definition in each oneOf.

That is interesting with the tooling support though, do you recall roughly long ago that was? If/then/else was added in draft7 (2018) so maybe it just hadn't had widespread adoption yet?

Copy link
Member Author

Choose a reason for hiding this comment

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

It was like a year or two ago

Copy link
Member Author

Choose a reason for hiding this comment

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

as we currently repeat the animated definition in each oneOf

Ah my bad, I thought you meant for layers

@mbasaglia mbasaglia marked this pull request as ready for review July 11, 2024 15:16
@mbasaglia
Copy link
Member Author

I think most of the validation is implemented, it would be great if people could test the validator and gave feedback

@mbasaglia mbasaglia added this to the 1.0 milestone Jul 11, 2024
@mbasaglia
Copy link
Member Author

Also, probably we want to extract the validator as a JS module and publish it for others to use as a library

@b-wils
Copy link
Contributor

b-wils commented Jul 23, 2024

I surfaced #65 while testing this out locally. Any ideas why this surfaced in your validation tooling but not other validators? Looks like it is using ajv so I'm surprised at the discrepancy. I also wonder if this could be one of the previous concerns with using "if"

@b-wils
Copy link
Contributor

b-wils commented Jul 24, 2024

Looks like this is flagging a and k as unknown properties as well.

@b-wils
Copy link
Contributor

b-wils commented Jul 24, 2024

In the interest of getting this in quickly so we can have it for the review period, what do people think about checking this in and we can migrate it's own repo/npm later? Not sure if it makes sense to do the warnings in a follow up if there are still some rough edges that may take time to work out.

@fmalita
Copy link
Member

fmalita commented Jul 25, 2024

Here's another failing sample: https://www.jsonschemavalidator.net/s/Klsfo2z4

Looks like the shape validation fails, but afaict it does match Rectangle - so not sure what's going on...

@mbasaglia
Copy link
Member Author

Looks like this is flagging a and k as unknown properties as well.

Fixed

@mbasaglia
Copy link
Member Author

Here's another failing sample: https://www.jsonschemavalidator.net/s/Klsfo2z4

Looks like the shape validation fails, but afaict it does match Rectangle - so not sure what's going on...

Validates ok on the validator

@mbasaglia
Copy link
Member Author

Added some custom validation for keyframes, for reference this is a json showing various cases:

{
    "fr": 60,
    "ip": 0,
    "op": 60,
    "w": 512,
    "h": 512,
    "layers": [
        {
            "ty": 4,
            "st": 0,
            "ip": 0,
            "op": 60,
            "ks": {},
            "shapes": [
                {
                    "ty": "el",
                    "s": {
                        "a": 0,
                        "k": [
                            200,
                            200
                        ]
                    },
                    "p": {
                        "a": 1,
                        "k": [
                            {
                                "_comment": "valid, has i/o",
                                "t": 0,
                                "s": [200, 200],
                                "i": {"x": 1, "y": 1},
                                "o": {"x": 0, "y": 0}
                            },
                            {
                                "_comment": "invalid t <= previous t",
                                "t": 0,
                                "s": [200, 200],
                                "i": {"x": 1, "y": 1},
                                "o": {"x": 0, "y": 0}
                            },
                            {
                                "_comment": "valid, has h = 1",
                                "t": 20,
                                "s": [200, 200],
                                "h": 1
                            },
                            {
                                "_comment": "invalid, has h = 0 but no i/o",
                                "t": 30,
                                "s": [200, 200],
                                "h": 0
                            },
                            {
                                "_comment": "invalid, needs i/o",
                                "t": 40,
                                "s": [200, 200]
                            },
                            {
                                "_comment": "valid, last frame",
                                "t": 50,
                                "s": [200, 200]
                            }
                        ]
                    }
                },
                {
                    "ty": "fl",
                    "c": {
                        "a": 0,
                        "k": [
                            0,
                            0,
                            0
                        ]
                    },
                    "o": {
                        "a": 0,
                        "k": 100
                    }
                }
            ]
        }
    ]
}

@mbasaglia
Copy link
Member Author

what do people think about checking this in and we can migrate it's own repo/npm later?

Yeah that was my idea, keep it here until we are ready to publish 1.0 so it's easier to develop

@b-wils
Copy link
Contributor

b-wils commented Jul 31, 2024

A couple more minor issues/feedback. Some of these are probably fine to wait for a separate PR

@mbasaglia
Copy link
Member Author

I think most of those points have been fixed. I think it would make sense to use the validator in unit tests as it can provide more granular output than simple pass/fail (it can tell which objects are failing)

@b-wils
Copy link
Contributor

b-wils commented Aug 1, 2024

I think most of those points have been fixed. I think it would make sense to use the validator in unit tests as it can provide more granular output than simple pass/fail (it can tell which objects are failing)

Yeah, this is looking great!

@heathmill
Copy link

Great to see! Let's get this in so we can start reviews, and can continue to iterate as needed.

@mbasaglia mbasaglia merged commit dbc8dc3 into lottie:main Aug 2, 2024
3 checks passed
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.

4 participants