valibot
valibot copied to clipboard
Proposal: Ternary operator
As discussed in #994 would be great to have a ternary validation operator that enables branching of validation.
It declaration should look something like this:
function ternary<
selectorSchema extends v.Schema,
positiveSchema extends v.Schema,
negativeSchema extends v.Schema
>(
selectorSchema: selectorSchema,
positiveSchema: positiveSchema,
negativeSchema: negativeSchema
)
type TernaryInput = v.InferInput<selectorSchema> | v.InferInput<negativeSchema>
type TernaryOutput = v.InferOutput<positiveSchema> | v.InferOutput<negativeSchema>
type TernaryIssues = v.InferIssue<positiveSchema> | v.InferIssue<negativeSchema>
When applied operator follows algorithm:
positive::=v.is(selectorSchema, input)- if
positive, then- apply
positiveSchema - return output and any issues ecountered by applying
positiveSchema
- apply
- else if not
positive, then- apply
negativeSchema - return output and any issues encountered by applying
negativeSchema
- apply
would be used something like this:
const fileLocationSchema = v.ternary(
v.url(),
// positiveSchema:
v.pipe(
v.startsWith('http', 'Only http based URLs are accepted'),
v.check(hasPort, 'URL should explicitly provide port to be used')
),
// negativeSchema:
v.pipe(
v.check(isPathLike, 'Should be path or URL'),
v.check(isAbsolutePath, 'Only absolute path is allowed')
)
)
v.parse(fileLocationSchema, 'ftp://@')
// ^ Error: Only http based URLs are accepted
v.parse(fileLocationSchema, './something')
// ^ Error: Only absolute path is allowed
v.parse(fileLocationSchema, ' some thing !!! ### ')
// ^ Error: Should be path or URL
Thank you for the great issue description. pipe requires a schema as its first argument (see our mental model guide). Therefore, I would probably change the API to:
const Schema = v.pipe(
v.string(),
v.ternary(
v.url(),
// positive actions:
[
v.startsWith('http', 'Only http based URLs are accepted'),
v.check(hasPort, 'URL should explicitly provide port to be used'),
],
// negative actions:
[
v.check(isPathLike, 'Should be path or URL'),
v.check(isAbsolutePath, 'Only absolute path is allowed'),
]
)
);
Another approach to the ternary API could be something similar to variant called strain (name is just an example), which decides which validation to choose based on a discriminator validation:
const Schema = v.pipe(
v.string(),
v.strain(
[v.email(), [v.endsWith('@org.com'), v.check(isEmailAvailable)]],
[v.check(isPhoneNumber), [v.check(isPhoneAvailable)]],
'Fallback error message'
)
);
Yep, strain looks much more versetile and "Fallback error" as a separate argument is much better than "Should be path or URL" in negative branch in my initial suggestion!
Yet, I don't think that we can really scale v.strain with arrays as arguments, because it'll quickly go out of hand with hundreds of Ts in generic declaration for 2 axes. So I would suggest something like this instead:
const Schema = v.pipe(
v.string(),
v.strain(
v.strainBranch(
v.email(),
v.endsWith('@org.com'),
v.check(isEmailAvailable)
),
v.strainBranch(
v.check(isPhoneNumber),
v.check(isPhoneAvailable)
),
'Fallback error'
)
)
I will probably focus on our v1 release before coming back to this issue. Feel free to explore the API design further (including completely different ideas) and share your findings. In the meantime, since Valibot is modular, you can always write your own schemas, actions and methods to support such a feature in your own codebase.
The ternary and strain features are exactly what I was looking for. If these functionalities were implemented as standard APIs, users would not be confused. Just as if and switch serve different use cases, I believe both should be implemented. I hope these features will be included as standard APIs in a future release!
Thanks for your feedback! Which API do you prefer? Do you have alternative solutions we should consider?
Thank you for the great issue description.
piperequires a schema as its first argument (see our mental model guide). Therefore, I would probably change the API to:const Schema = v.pipe( v.string(), v.ternary( v.url(), // positive actions: [ v.startsWith('http', 'Only http based URLs are accepted'), v.check(hasPort, 'URL should explicitly provide port to be used'), ], // negative actions: [ v.check(isPathLike, 'Should be path or URL'), v.check(isAbsolutePath, 'Only absolute path is allowed'), ] ) ); Another approach to the
ternaryAPI could be something similar tovariantcalledstrain(name is just an example), which decides which validation to choose based on a discriminator validation:const Schema = v.pipe( v.string(), v.strain( [v.email(), [v.endsWith('@org.com'), v.check(isEmailAvailable)]], [v.check(isPhoneNumber), [v.check(isPhoneAvailable)]], 'Fallback error message' ) );
This function signature is consistent and looks very good!
Hi, @BerkliumBirb. I'm Dosu, and I'm helping the Valibot team manage their backlog. I'm marking this issue as stale.
Issue Summary:
- You suggested adding a ternary validation operator for more flexible logic.
- Fabian-hiller proposed an alternative API design called
strain. - You agreed with the
strainapproach but suggested a different implementation. - Fabian-hiller mentioned focusing on the v1 release before revisiting this feature.
- bmthd expressed strong support for both
ternaryandstrainfunctionalities.
Next Steps:
- Please let me know if this issue is still relevant to the latest version of the Valibot repository by commenting here.
- If there is no further activity, I will automatically close this issue in 30 days.
Thank you for your understanding and contribution!
The strain API seems similar to what we have in mind with and and or in issue #835. I think we will introduce such an API in the long run but some more research is required.
Hi, @BerkliumBirb. I'm Dosu, and I'm helping the Valibot team manage their backlog and am marking this issue as stale.
Issue Summary:
- You proposed adding a ternary validation operator to simplify complex validation schemas.
- Maintainer fabian-hiller suggested an alternative API called
strain. - You found
strainversatile but proposed refinements for scalability. - Another user supported both
ternaryandstrainas standard APIs. - Fabian-hiller plans to focus on the v1 release first and revisit this feature later after more research.
Next Steps:
- Please let me know if this feature is still relevant to the latest version of Valibot by commenting on this issue.
- If I don’t hear back within 30 days, the issue will be automatically closed.
Thanks for your understanding and contribution!