-
-
Notifications
You must be signed in to change notification settings - Fork 204
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
Improve performance and issues for nested variants #809
Conversation
@ZerNico the new algorithm returns the same result for both writing styles of nested variants: import * as v from 'valibot';
const Schema1 = v.variant('kind', [
// kind: 'A'
v.variant('type', [
v.object({
kind: v.literal('A'),
type: v.literal('A'),
}),
v.object({
kind: v.literal('A'),
type: v.literal('B'),
}),
]),
// kind: 'B'
v.variant('type', [
v.object({
kind: v.literal('B'),
type: v.literal('A'),
}),
v.object({
kind: v.literal('B'),
type: v.literal('B'),
}),
]),
]);
const Schema2 = v.variant('kind', [
v.variant('type', [
// kind: 'A'
v.object({
kind: v.literal('A'),
type: v.literal('A'),
}),
v.object({
kind: v.literal('A'),
type: v.literal('B'),
}),
// kind: 'B'
v.object({
kind: v.literal('B'),
type: v.literal('A'),
}),
v.object({
kind: v.literal('B'),
type: v.literal('B'),
}),
]),
]); By also supporting an array as the first argument, we could even support a third writing style: import * as v from 'valibot';
const Schema3 = v.variant(
['kind', 'type'],
[
// kind: 'A'
v.object({
kind: v.literal('A'),
type: v.literal('A'),
}),
v.object({
kind: v.literal('A'),
type: v.literal('B'),
}),
// kind: 'B'
v.object({
kind: v.literal('B'),
type: v.literal('A'),
}),
v.object({
kind: v.literal('B'),
type: v.literal('B'),
}),
]
); With a few small tweaks, the new algorithm could easily support the third option, making our API even more flexible. However, there are some drawbacks. It increases the bundle size by about 15 to 20 bytes. This doesn't sound like much, but the new algorithm has already increased the bundle size by about 70 bytes. So we would increase it even more just to support an additional writing style. Another drawback is that if we support both a single discriminator key and a list of discriminator keys as the first argument, our API becomes more complicated and harder to learn and understand. We could force users to always specify an array even for a single discriminator key, but that would introduce a breaking change (which is ok since we are still in v0). I look forward to getting feedback on this. |
commit: |
I will merge this now. However, you can still give me feedback. |
@fabian-hiller sounds like a very good solution. Also thanks for the quick fix, you are awesome :) For allowing multiple discriminators I am not sure I'd like the breaking change to force setting the keys as an array. Even if it's still v0 it might not be super wise to annoy users with breaking changes for features most will probably not use. Also makes the usage a bit more verbose for everyone. |
Thanks for your feedback. Let's keep it as is for now, and in the long run I will consider supporting both a string and an array of strings for the first argument if more users request this API design. |
Fix #794
I have implemented a completely new algorithm for
variant
that supports multiple nestes discriminator keys. The following describes how the algorithm works.The algorithm searches for the correct object schema to use to validate the input based on the specified discriminator keys. It gathers information about the first deepest invalid discriminator, if any. Discriminators present in the input have priority over missing ones. An object schema is used for validation only if all specified discriminators are valid. If no object schema is found that matches the specified discriminators,
variant
will use the collected information about the first deepest invalid discriminator to return a useful issue.