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

feat: Implement standard schema interface #2258

Open
wants to merge 11 commits into
base: master
Choose a base branch
from

Conversation

logaretm
Copy link

@logaretm logaretm commented Dec 4, 2024

What

This is a PR that implements the standard schema interface for yup.

Motivation: Standard schema is an initiative that is aimed to get all Typed schema providers to support a unified interface that will enable various tools and 3rd party libraries to seamlessly integrate with "a schema provider" which reduces friction when migrating from one provider to the other, and allows mixing these providers if one is suited for a task more than the rest. Another benefit is it allows 3rd party authors to ditch the "resolver" pattern which in turn reduces their users' friction.

We discussed this briefly in #2255 with no clear green light given on this, so I understand if this is something you don't want the burden of maintaining. I already did the work locally to play with it, since I was planning to build a yup standard schema adapter anyways. So, I thought I might as well just PR it.

I made sure to add tests and type tests as well, happy to address any issues in this PR.

How

To avoid adding @standard-schema/spec as a dependency, I copied the types which is the recommended approach. I then make sure it is aligned with the spec by testing it against the spec which I added as a dev dependency.

I also had to implement a path splitter to make the paths compatible with the standard schema output.

Bundle size diff (~3%)

Label Size Before Size After
Bundle Size 72.6 KB 75.73 KB
Minified Size 39.07 KB 40.08 KB
Gzipped Size 11.44 KB 11.79 KB

closes #2255

@logaretm logaretm force-pushed the feat/implement-standard-schema branch from 70eb7f4 to 9ca5949 Compare January 5, 2025 12:59
@jquense
Copy link
Owner

jquense commented Feb 8, 2025

I see this and appreciate your work here, i'm trying to get some time to dedicate to looking at it!

expect(verifyStandardSchema(object())).toBe(true);
expect(verifyStandardSchema(date())).toBe(true);
expect(verifyStandardSchema(mixed())).toBe(true);
expect(verifyStandardSchema(tuple([mixed()]))).toBe(true);
Copy link
Owner

Choose a reason for hiding this comment

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

this is missing lazy

Copy link
Author

Choose a reason for hiding this comment

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

Added it, along with a special test for it.

src/schema.ts Outdated
@@ -202,6 +214,11 @@ export default abstract class Schema<
this.withMutation((s) => {
s.nonNullable();
});

this['~standard'] = createStandardSchemaProps<
Copy link
Owner

Choose a reason for hiding this comment

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

this won't work correctly, b/c it closes over the schema instance. Most method calls in yup create new schema instances via cloning and the validate method won't keep up with them, e.g. string().required()['~standard'].validate will be the nonRequired schema instance

Copy link
Author

Choose a reason for hiding this comment

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

You are right, I re-implemented them as getters now which should carry over well with cloning. I added a couple of tests to test that as well.

// Track if we're inside quotes (for property names with special chars)
let inQuotes = false;

for (let i = 0; i < path.length; i++) {
Copy link
Owner

Choose a reason for hiding this comment

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

what is going on with path logic? There are already utilities for splitting and traversing yup's path's in utils, see the reach utility

Copy link
Author

Choose a reason for hiding this comment

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

Here I'm not traversing the schema path which is what I think reach and getIn are for?

What I'm doing here is I'm converting error path from as single string value to an array of strings/symbols which is what the standard schema interface requires.

For example these are the output paths from ValidationErrors and next to them is how they should look like in standard schema:

Error Message Path Array Format
obj.foo ['obj', 'foo']
obj["not.obj.nested"] ['obj', 'not.obj.nested']
arr[0].foo ['arr', '0', 'foo']
arr[0]["not.array.nested"] ['arr', '0', 'not.array.nested']
["not.a.field"] ['not.a.field']

I scanned the codebase quickly, do we have utilities for this kind of thing?

segments.push(currentSegment);
} else {
// Handle quoted property names (e.g. obj["foo.bar"])
segments.push(currentSegment.replace(/^"|"$/g, ''));
Copy link
Owner

Choose a reason for hiding this comment

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

i don't think yup even handles these cases, i'm not sure it makes sense to do it here, it's misleading, b/c validate will still likely treat these as actual path segments

Copy link
Author

Choose a reason for hiding this comment

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

Right, I didn't really encounter this in all my time using yup so I didn't consider if it was supported or not. What do you think I should do then?

Copy link
Owner

Choose a reason for hiding this comment

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

can we add lot more diverse and exhaustive tests around this interface?

Copy link
Author

Choose a reason for hiding this comment

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

Absolutely, I'm relying on the other parts working as expected because this only adapts the interface to yup's current implementation so I was only testing that layer.

Happy to add more tests, what kind of tests would you like to see? General ones for each schema?

@logaretm logaretm requested a review from jquense February 8, 2025 19:12
@logaretm
Copy link
Author

logaretm commented Feb 8, 2025

Thanks for taking a look, I addressed some of the issues and added clarification to your comments on the path stuff. Happy to keep iterating with your guidance.

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.

Support Standard-schema API?
2 participants