Comments (28)
No, but that's an interesting idea!
I think so, in my current implementation, this is important to select the duplicated option, and with the code that I've shared here, it works.
With my current code pipeline actions accept a
dataset
as the first argument and return adataset
as a result. This will allow you to easily write your own actions and add as manyissues
as you want. I plan to publish a first draft next week.
Those are great news, I'm looking forward to testing it.
from valibot.
Although it's not recommended, I'll let v.custom
with throw
as it is working as I need, I'll come here again when the rewrite is done to update it. And perhaps close the issue then with a solution.
In summary, I would like to have:
- An option to validate every element of the array and add the issue to the index of the occurrence (in this example,
otherNationalities.2
. - An option to add issues globally to the schema based on field relations:
const Schema = v.object(
{
mainNationality: v.string([v.minLength(1, 'required.nationality')]),
otherNationalities: v.array(v.string([v.minLength(1, 'required.otherNationalities')]), [
v.minLength(1, 'required.otherNationalities'),
(custom valiration to check duplicated)
])
(...other fields)
},
[
v.<someMethod>((inputs) => {
// If some element in otherNationalities is equal to the mainNationality,
// add an issue to the otherNationalities item index
}),
],
);
from valibot.
Oh, that's what I need, I thought that the custom
was deprecated. Thanks. I'll play a bit with the current state of the lib.
Please update this issue when this action gets done.
from valibot.
You are right. I will probably add it today or tomorrow. I will ping you then.
from valibot.
I am working on it and will probably add it later today.
from valibot.
Thanks, I'll play with it again.
from valibot.
Feel free to create a new issue (or PR) to add an items
action in the next weeks.
from valibot.
Is this issue resolved? I will close it for now, but will reopen it if not.
I'll check it ASAP and let you know.
Feel free to create a new issue (or PR) to add an
items
action in the next weeks.
I'll open one issue latter today.
from valibot.
I agree, let's do the following, I'll close this issue and open a new one with a recap of this one.
from valibot.
Don't throw inside of custom
. Instead always return a boolean: https://valibot.dev/api/custom/
You can forward issues with this method: https://valibot.dev/api/forward/
from valibot.
Hum, I saw some issues where people were throwing inside custom
.
Imagine this scenario, how can I achieve the same result without throwing in custom?
codOutrasNacionalidades: v.array(v.string([v.minLength(1, 'required.otherNationalities')]), [
v.minLength(1, 'required.otherNationalities'),
v.custom((input) => {
const duplicates = input.filter((item, index) => input.indexOf(item) !== index);
const issues: v.SchemaIssues = [] as unknown as v.SchemaIssues;
if (duplicates.length > 0) {
input.forEach((val, index) => {
if (duplicates.includes(val)) {
issues.push(
createValibotIssue({
fieldPath: `pessoa.codOutrasNacionalidades.${index}`,
input: { 'pessoa.codOutrasNacionalidades': input },
message: 'validation.uniqueNationalities',
reason: 'array',
}),
);
}
});
}
if (issues.length > 0) {
throw new v.ValiError(issues);
}
return true;
}),
]),
export const createValibotIssue = ({
message,
reason,
input,
fieldPath,
}: Pick<SchemaIssue, 'message' | 'reason'> & { input: Record<string, unknown>; fieldPath: string }): SchemaIssue => ({
context: '',
expected: null,
input: input[fieldPath],
message,
path: [
{
input,
key: fieldPath,
origin: 'value',
type: 'object',
value: input[fieldPath],
},
],
reason,
received: '',
});
from valibot.
I would return false
instead of throwing and error and add the error message as the second parameter to custom
. But currently there is no way to return multiple issues, but I am in the process of rewriting Valibot and it will be easier then.
from valibot.
Also we have a some
and every
validation action specifically for arrays. You could use every
to check for duplicate values.
from valibot.
I would return
false
instead of throwing and error and add the error message as the second parameter tocustom
. But currently there is no way to return multiple issues, but I am in the process of rewriting Valibot and it will be easier then.
I've seen the discussion, I'm waiting for that :).
Also we have a
some
andevery
validation action specifically for arrays. You could useevery
to check for duplicate values.
I didn't try it yet, but do every
put the error at the index of the element?
from valibot.
I didn't try it yet, but do
every
put the error at the index of the element?
No, but that's an interesting idea!
I've seen the discussion, I'm waiting for that
With my current code pipeline actions accept a dataset
as the first argument and return a dataset
as a result. This will allow you to easily write your own actions and add as many issues
as you want. I plan to publish a first draft next week.
from valibot.
I plan to publish a blog post in two or three weeks about the results and investigations of the new pipe
function implementation as well as the rewrite of the library. For now, I expect the bundle size to be smaller, the performance to be faster and the types to be more accurate.
from valibot.
Hi @fabian-hiller I saw your comment on the rewrite PR, I was thinking about testing the new implementation of pipe
in this context, do you have any suggestion on where I can start? Or there are no way to do this yet?
from valibot.
It is possible, but you have to write your own action. The concept is very simple. Here is an example where I have called the action "items":
import {
_addIssue,
type BaseIssue,
type BaseValidation,
type ErrorMessage,
} from 'valibot';
/**
* Items issue type.
*/
export interface ItemsIssue<TInput extends unknown[]>
extends BaseIssue<TInput> {
/**
* The issue kind.
*/
readonly kind: 'validation';
/**
* The issue type.
*/
readonly type: 'items';
/**
* The expected input.
*/
readonly expected: null;
/**
* The validation function.
*/
readonly requirement: (input: TInput[number]) => boolean;
}
/**
* Items action type.
*/
export interface ItemsAction<
TInput extends unknown[],
TMessage extends ErrorMessage<ItemsIssue<TInput>> | undefined,
> extends BaseValidation<TInput, TInput, ItemsIssue<TInput>> {
/**
* The action type.
*/
readonly type: 'items';
/**
* The action reference.
*/
readonly reference: typeof items;
/**
* The expected property.
*/
readonly expects: null;
/**
* The validation function.
*/
readonly requirement: (input: TInput[number]) => boolean;
/**
* The error message.
*/
readonly message: TMessage;
}
/**
* Creates an items validation action.
*
* @param requirement The validation function.
*
* @returns An items action.
*/
export function items<TInput extends unknown[]>(
requirement: (input: TInput[number]) => boolean
): ItemsAction<TInput, undefined>;
/**
* Creates an items validation action.
*
* @param requirement The validation function.
* @param message The error message.
*
* @returns An items action.
*/
export function items<
TInput extends unknown[],
const TMessage extends ErrorMessage<ItemsIssue<TInput>> | undefined,
>(
requirement: (input: TInput[number]) => boolean,
message: TMessage
): ItemsAction<TInput, TMessage>;
export function items(
requirement: (input: unknown) => boolean,
message?: ErrorMessage<ItemsIssue<unknown[]>>
): ItemsAction<unknown[], ErrorMessage<ItemsIssue<unknown[]>> | undefined> {
return {
kind: 'validation',
type: 'items',
reference: items,
async: false,
expects: null,
requirement,
message,
_run(dataset, config) {
if (dataset.typed) {
for (let index = 0; index < dataset.value.length; index++) {
const item = dataset.value[index];
if (!this.requirement(item)) {
_addIssue(this, 'item', dataset, config, {
input: item,
path: [
{
type: 'array',
origin: 'value',
input: dataset.value,
key: index,
value: item,
},
],
});
}
}
}
return dataset;
},
};
}
Now you can write the following code:
import * as v from 'valibot';
import { items } from './your-path';
const Schema = v.pipe(
v.array(v.string()),
items((item) => item.startsWith('foo'), 'Your message')
);
from valibot.
Thanks. I'll try that, do you plan on implementing it in valibot?
from valibot.
Yes, I will consider it. Do you have some good alternatives names for the action?
from valibot.
The only one that I could think of is iterate
.
from valibot.
I was thinking, it would be nice if the callback had 2 or 3 arguments (item, index, items) => boolean
.
With that we could create validations based on other items, for example, identify duplicated values.
items((item, index, items) => items.filter((v)=> v===item).length > 1, 'Duplicated')
Let me know what you think.
Another requirement I can think that would be great is an action to validate properties based on other properties. Let me give you an example:
{
"primaryEmail": "[email protected]",
"otherEmails": ["[email protected]", "[email protected]"]
}
To validate that the primaryEmail
is not present in otherEmails
the items
action doesn't work, I need some actions that allow me to add issues globally.
I hope I didn't confuse you.
from valibot.
The only one that I could think of is
iterate
.
Thanks! Will think about it! Both names could work.
I was thinking, it would be nice if the callback had 2 or 3 arguments
(item, index, items) => boolean
.
I agree!
To validate that the
primaryEmail
is not present in...
This requires a custom validation in the pipeline of the object definition with a forward to the appropriate field. Note: We renamed custom
to check
with the rewrite.
from valibot.
@fabian-hiller I was playing around and found that the forward
action is missing.
from valibot.
Done
from valibot.
Is this issue resolved? I will close it for now, but will reopen it if not.
from valibot.
I'm not able to put a schema to work with this requirement, can you help here?
{ "primaryEmail": "[email protected]", "otherEmails": ["[email protected]", "[email protected]"] }To validate that the
primaryEmail
is not present inotherEmails
theitems
action doesn't work, I need some actions that allow me to add issues globally.
The forward
action doesn't work because I cannot put the key and index of the duplicated email, in this case otherEmails.1
.
One possible solution that came to my mind is a method that allow us to add issues to the list of issues already created by valibot validations. Something like:
v.someMethod((inputs, ctx) => {
// ...(my custom validation with ctx.addIssue())...
return ctx.issues // Or other type of return
})
from valibot.
Maybe we should add an advanced refine
method (similar to Zod's superRefine
) that allows you to directly interact with the input and output dataset of the method and not only with the raw value.
from valibot.
Related Issues (20)
- Type instantiation is excessively deep and possively Infinite HOT 4
- [i18n] Add Spanish language HOT 1
- Empty array in optional as a default value turns the type into union of the type or never HOT 6
- Build error HOT 4
- Add `items` action HOT 1
- Can't run test code using 0.31.0-rc HOT 6
- Add an advanced `refine` method (similar to Zod's `superRefine`) HOT 3
- [0.31.0-rc] Enable to perform transform on the first argument of pipe method HOT 2
- EMOJI_REGEX throws Invalid regular expression flags on node v18 HOT 4
- TypeScript: InferInput always infers intersect as 'never' HOT 3
- [v0.31.0-rc.5] `Invalid type: Expected Object but received Object` because of `edge` runtime HOT 3
- abortPipeEarly influnces on abortEarly HOT 2
- Compiled type for actions missing typing for 'requirement' in ErrorMessage HOT 2
- [v0.31.0-rc.5] The internal function `_stringify` has a problem HOT 23
- cannot pipe a pipe HOT 2
- Enum error with React Hook Form HOT 6
- Reduce boilerplate for custom actions HOT 2
- Forward is changing the issues paths on flatten with an error in the forwarded property HOT 3
- @valibot/i18n could not be installed HOT 1
- Pipe to emit a single issue
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from valibot.