Skip to content

feat: Implement standard schema interface#2258

Merged
jquense merged 16 commits intojquense:masterfrom
logaretm:feat/implement-standard-schema
Aug 1, 2025
Merged

feat: Implement standard schema interface#2258
jquense merged 16 commits intojquense:masterfrom
logaretm:feat/implement-standard-schema

Conversation

@logaretm
Copy link
Contributor

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

// 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
Contributor 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
Contributor 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
Contributor 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?

Copy link
Owner

Choose a reason for hiding this comment

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

I would take a number of the other object, array, and lazy tests and test that they produce the same results as the primary yup interface, at least in turns of valid vs invalid.

The ones i'm thinking about in particular are around concat, extend, as well as conditionals like when and and references

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just got back around to doing this, so I had AI add test cases for various random examples for arrays, objects, and lazy to ensure the standard schema interface produces the same errors as the main API.

I also had it write tests for conditionals with when and extend and concat APIs and the implementation seems to hold in these cases as well.

Let me know if you think this is acceptable and thank you for following up!

@logaretm logaretm requested a review from jquense February 8, 2025 19:12
@logaretm
Copy link
Contributor 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.

@anton-patrushev
Copy link

What's the plan here? Is there a chance this could be merged in the upcoming future?
cc: @logaretm

And btw, thanks for looking into this @logaretm 🙌 ❤️

I would love to see this PR merged to get myself unblocked with the upgrade TanStack Form and still have my yup validator integrations working and postponing, for now, the change and migration to a different object validation solutions like zod, etc.

@jquense
Copy link
Owner

jquense commented Jun 17, 2025

Ok @logaretm sorry for being MIA, I would like to get this done, so if you arte still up for it i can be more responsive and quicker than responding every few months :P

@franciscohermida
Copy link

Not speaking for logaretm so this must be confirmed, but it could be too late now as the solution was to drop support for yup in one of his libraries moving forward.

@logaretm
Copy link
Contributor Author

logaretm commented Jul 13, 2025

@franciscohermida I halted the release that would drop it to find time for this one, I will try to get this one merged then figure out what to do on my libraries ecosystem.

@jquense No worries, I'm too familiar with the open-source life 😂 I will pick this up with your guidance and I will try to address the issues you raised.

@logaretm logaretm force-pushed the feat/implement-standard-schema branch from f640f6b to b72887c Compare July 28, 2025 21:08
@logaretm
Copy link
Contributor Author

@jquense I added more tests around the areas you requested, I used AI to do the bulk of the work. Hopefully this should be acceptable, the implementation seems to be holding well.

@jquense
Copy link
Owner

jquense commented Aug 1, 2025

Looks great, i need to figure out why CI pipeline is broken.

Can you add a few docs to the readme just noting that it's standard schema compatible

@logaretm
Copy link
Contributor Author

logaretm commented Aug 1, 2025

Great, thank you! I added a feature item and a section to the README 🙌

@jquense jquense merged commit ced5f51 into jquense:master Aug 1, 2025
1 check failed
@jquense
Copy link
Owner

jquense commented Aug 1, 2025

released in v1.70 Thank you very much @logaretm 🎉

@dlindahl
Copy link

dlindahl commented Aug 8, 2025

@logaretm Wanted to raise a potential issue with you regarding how array accessors are typed in this implementation of Standard Schema. I cannot find any specific definition, but there is at least a difference in how yup handles this versus zod.

Specifically, array accessor path segments are parsed as a numerical string (i.e. "0") rather than a literal number (i.e. 0). This trips up @tanstack/form because when it reconstitutes the path segments into a path to use as a key in its error state object, it performs a typeof check on the path segment in order to determine if its an array accessor or not. Since its a string, this check fails, and it treats it as a property accessor instead.

More info is available in this Issue I opened at TanStack/form#1683.

When I swapped yup for zod, @tanstack/form built the appropriate path and the feature worked as expected. So it would at least appear as if zod is building the array accessor path segment as a literal Number since the typeof check passes.

It is unclear to me if this is an ambiguous aspect of Standard Schema that @tanstack/form needs to expect (and Standard Schema should clarify) or if this is a bug in this implementation of Standard Schema in yup.

Either way, I wanted to raise the issue and get it documented so people are at least aware.

@logaretm
Copy link
Contributor Author

logaretm commented Aug 8, 2025

@dlindahl I don't think it was a requirement for the standard schema spec, at least I'm not aware of it.

I believe we could parse them as numbers relatively simple since we know when it is an array indices:

if (char === ']' && !inQuotes) {
if (currentSegment) {
// Handle numeric indices (e.g. arr[0])
if (/^\d+$/.test(currentSegment)) {
segments.push(currentSegment);

The libraries I maintain don't care much about that difference between the path segment types.

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?

5 participants