fabian-hiller / valibot Goto Github PK
View Code? Open in Web Editor NEWThe modular and type safe schema library for validating structural data ๐ค
Home Page: https://valibot.dev
License: MIT License
The modular and type safe schema library for validating structural data ๐ค
Home Page: https://valibot.dev
License: MIT License
Thanks for your great library.
I think multilingual support is important for this library.
For example, our company chose dayjs instead of date-fns because i18n is far more easy to apply Japanese.
Would you please consider support i18n?
Add an option i18n
to parse
function:
parse(input: unknown, info?: ParseInfo, i18n?: Record<string, string>)
And get message from i18n in each function:
throw new ValiError([
{
validation: 'ends_with',
origin: 'value',
message: error || i18n?.["end_with"] || 'Invalid end',
input,
...info,
},
]);
So user can only define the i18n for the functions they're using to reduce bundle size. I'm not sure this implementation is OK for this library.
Hey,
There are also more use cases for valibot. One would be to validate the data that is stored in the Localstorage. And another use case would be to validate the schema of your URL search parameters.
Hi! Thank you very much for this library. I do very appreciate the focus on performance and very high composability of rules! It's super awesome! Also congratulations of a first release!
I came here with this issue, because to this day I'm using Zod
, since it's doing fine for me so far, but my biggest nitpick there is that there is no easy way to declare conditional requiring of the object properties. I wonder if there is a possibility to do that here
I mean that you can mark an object property as required (I'm assuming that's by default here), but only when given condition is met
f.e.
import { parse, object, string, requiredWhen } from 'valibot';
function getFormValidationSchema(dataToValidate) {
const formSchema = object({
character: {
type: string(),
},
shurikensAmount: number([
requiredWhen(() => dataToValidate.character.type === 'ninja'),
minRange(1),
maxRange(3)
]),
});
return formSchema;
}
const formValidationSchema = getFormValidationSchema(data);
parse(formValidationSchema)
With data like this
type CharacterType = 'ninja' | 'warrior' | 'wizard';
const data = {
character: {
type: 'ninja' as CharacterType
},
shurikensAmount: null
};
parse()
should throw an error, because shurikensAmount
is null
and it's required for character.type === 'ninja'
but with data like this
type CharacterType = 'ninja' | 'warrior' | 'wizard';
const data = {
character: {
type: 'wizard' as CharacterType
},
shurikensAmount: null
};
should be fine, since wizards are not using shurikens
I'm not sure if this is a good idea or not. I'm only giving an idea for a solution for my problem where I struggled with trying to achieve this in Zod. I had to use refine()
in this case, but it was more of a workaround rather than proper solution.
link: colinhacks/zod#938 (comment)
Since this library focus on high composability of rules, I wonder if it there is a possibility to do that here.
If this is not a good idea, I will appreciate proper explanation
Have a good day!
When using Valibot in a React project, as demonstrated by this StackBlitz example,
Just using useDefault
at top-level like const schema = useDefault(string(), 'test')
causes the following ESLint error:
3:16 error React Hook "useDefault" cannot be called at the top level. React Hooks must be called in a React function component or a custom React Hook function react-hooks/rules-of-hooks
This error is caused by eslint-plugin-react-hooks, which is maintained by the React team and recommended officially in the doc.
Basically every well maintained React projects should have installed this ESLint rule.
Semantically, useSomeIdentifierHere
is considered as a React hook by its naming convention and tools like the ESLint rule is following this definition. Note that this is not only about ESLint, other tools such as Fast Refresh implementation is also relying on this naming convention. People might be confused since useDefault
looks like a React hook as well.
Usually it's weird to be constrained by "just a single framework" such as React but React is used extremely a lot and it would be nice if Valibot can be a good companion of React.
I searched Valibot repo and did the following Ripgrep search:
$ valibot/library rg 'use[A-Z]'
src/methods/index.ts
14:export * from './useDefault/index.ts';
src/methods/useDefault/index.ts
1:export * from './useDefault.ts';
src/methods/useDefault/useDefault.test.ts
4:import { useDefault } from './useDefault.ts';
6:describe('useDefault', () => {
8: const schema1 = useDefault(string(), 'test');
src/methods/useDefault/useDefault.ts
11:export function useDefault<TSchema extends BaseSchema | BaseSchemaAsync>(
So we only need to think about an alternative name of useDefault
.
My suggestion so far is to rename it to something like withDefault
but there might be a better name
Hi,
I don't know how this would affect bundle size, but I think it would be interesting to have an API like :
const reportSchema = formData({
title: string(),
content: string(),
photo: file(),
});
It could be useful in server actions
(Next.js) and client-side validations in <form>
.
Hello and first of all, thank you for your work with this library.
I was eager to migrate from zod
to valibot
after encountering this error on the use of schemas with many union
and transform
but the same one seems to occur.
Is there maybe a good practice to avoid it?
Thank you
Hello,
In many cases like for forms, we need to display all the errors at the same time and not one by one. So I think you should support returning all errors instead of throwing the first occured error.
Take this object, created with zod:
const ZodProblemDetailsSchema = z.object({
errors: z.record(z.array(z.string())).optional(),
});
When we infer the type of this schema with the z.infer method, we see that the type inferred for the Record is quite simple:
type ZodProblemDetails = {
errors?: Record<string, string[]> | undefined;
}
I've implemented the same thing with valibot:
const ProblemDetailsSchema = object({
errors: optional(record(array(string()))),
});
The type inferred with Output gives this:
type ProblemDetails = {
errors: RecordOutput<StringSchema, ArraySchema<StringSchema<string>, string[]>> | undefined;
}
Would it be possible to come up with a type similar to zod Records for valibot Records? They seem more readable / simple to understand!
Thank you!
Trying to validate the datetime "2023-08-05 14:41:39.589Z" with isoDateTIme validator, I got an error so, inspecting the implementation I found there is no case to considering an ommited separator and ISO 8601-1:2019 allows the T to be omitted in the extended format.
Maybe it could be the case of creating a extendedIsoDateTime validator in validations folder?
How can I achieve a similar functionality to Zod's discriminatedUnion
API in Valibot? I want to enable dynamic properties in an object.
discriminatedUnion
api:const response = z.discriminatedUnion("status", [
z.object({
status: z.literal("success"),
data: z.string(),
}),
z.object({
status: z.literal("failed"),
error: z.instanceof(Error),
}),
]);
myUnion.parse({
status: "success",
data: "yippie ki yay",
});
zod's default()
only works with undefined and not null, which this library perfectly mimics. Zod Sandbox Example
Thanks to catch()
on the other hand, it is possible to have a default value when validation fails. But Valibot seems to not have catch()
.
It is one of the most useful functions of zod (atleast to me) and I use it a lot. Especially with react, where I want the ensure the app always has certain pieces of data.
Thanks to the simplicity of Valibot is was able to quickly write a catch method.
import type { BaseSchema, Output } from 'valibot';
import { ValiError } from 'valibot';
function Catch<TSchema extends BaseSchema>(
schema: TSchema,
value: Output<TSchema>,
callback?: (err: Error) => void
): TSchema {
return {
...schema,
parse(input, info) {
try {
return schema.parse(input, info);
} catch (err: any) {
if (typeof callback === 'undefined') {
console.error(err);
} else {
callback(err);
}
return value;
}
},
};
}
Sandbox with usage examples
npm run fallback
This method could also be called fallback. I originally called it that, but to stay true to zod's naming I changed it to Catch, just not catch (reserved word).
First of all I recommend turning on discussions since technically speaking this is not an issue.
I'd like to ask how those 300 bytes in README in a sentence "Small bundle size starting at less than 300 bytes" were determined.
Did you import only let's say string? Or number? Or something else?
Thank you.
I have forked your project to have a look and I noticed a small thing. The tsup
config file has no minify property. Was it intended to not put it in there?
Not sure how it will effect bundle size in general and I would like to learn more.
I've just in case put a comparison between disabling and enabling.
When minify
is set to false
the javascript bundle size exceeds to:
When minify
is set to true
the javascript bundle size exceeds to:
I can make a PR if you wish to implement or you see don't have to.
Hi @fabian-hiller, your libs are amazing! But can you share with me how to custom property in an object like Zod does?
I have a generic typing function like this
export const baseQuerySchema = <T>() =>
object({
order: custom<`${string & keyof T}:${"asc" | "desc"}`>((val) =>
/\w+:(asc|desc)/.test(val as string),
),
pageSize: optional(transform(useDefault(string(), "20"), (v) => parseInt(v, 10))),
pageIndex: optional(transform(useDefault(string(), "0"), (v) => parseInt(v, 10))),
})
How can I transform order
filed to valibot ๐ The typescript compiler complains
No overload matches this call.
Overload 1 of 2, '(object: ObjectShape, pipe?: Pipe<{ [x: string]: any; }>): ObjectSchema<ObjectShape, { [x: string]: any; }>', gave the following error.
Type '(input: `${string & keyof T}:asc` | `${string & keyof T}:desc`, info: ValidateInfo) => `${string & keyof T}:asc` | `${string & keyof T}:desc`' is not assignable to type 'BaseSchema<any, any>'.
Overload 2 of 2, '(object: ObjectShape, error?: string, pipe?: Pipe<{ [x: string]: any; }>): ObjectSchema<ObjectShape, { [x: string]: any; }>', gave the following error.
Type '(input: `${string & keyof T}:asc` | `${string & keyof T}:desc`, info: ValidateInfo) => `${string & keyof T}:asc` | `${string & keyof T}:desc`' is not assignable to type 'BaseSchema<any, any>'.ts(2769)
Thanks for reading this!
I love the idea of your library, so let's try some things out to see how it works.
But I found some errors that didn't give me a clear error message; maybe something needs to be fixed on my side or your side.
I created a Runkit example so you can check it out: https://runkit.com/devbyrayray/testing-valibot
Hello,
In zod, I was used to bump my head around trying too many times to extend
a transformed schema.
With valibot, I refactored my code with merge
and did not encounter any errors BUT the merged schema (that uses transform
) was the input
instead of the output
of the transformation. Is it intended?
Otherwise, what is the correct way to do it?
Thank you
This is a tracking issue to discuss & improve the performance of Valibot.
I created a benchmark suite for Valibot so that we can track its runtime performance in many situations since existing benchmarks were failing to capture the real world schema and data diversity.
The current latest result can be checked from https://naruaway.github.io/valibot-benchmarks/
Currently we see the following interesting observations:
I'll continue improving my benchmark suite and will post any interesting information here.
We already have several performance improvement PRs: https://github.com/fabian-hiller/valibot/pulls?q=is%3Apr+is%3Aopen+label%3Aperformance
I'll post benchmark result for each PR later
Hello there!
At the moment there seems to be no way to use a recursive schema.
Zod for example does it like this:
const baseCategorySchema = z.object({
name: z.string(),
});
type Category = z.infer<typeof baseCategorySchema> & {
subcategories: Category[];
};
const categorySchema: z.ZodType<Category> = baseCategorySchema.extend({
subcategories: z.lazy(() => categorySchema.array()),
});
Maybe there even is a way to do this without having to manually define a type, I know some validation lib had that feature, I just can't remember which one it was. It might not be possible with the way Valibot works, though.
I write a simple benchmark with real case.
import Benchmark from "benchmark";
import { z } from "zod";
import * as yup from "yup";
import Joi from "joi";
import * as valibot from "valibot";
const SUITE_NAME = "";
const suite = new Benchmark.Suite("Validate Benchmark");
const value = {
latitude: 10,
longitude: 10,
scale: 10,
name: "",
address: "",
powerLevel: "low",
};
const stringSchema = z.object({
latitude: z.number(),
longitude: z.number(),
scale: z.number().min(5).max(18),
name: z.string().optional(),
address: z.string().optional(),
powerLevel: z.enum(["low", "medium", "high"]),
});
const yupSchema = yup.object({
latitude: yup.number(),
longitude: yup.number(),
scale: yup.number().min(5).max(18),
name: yup.string().optional(),
address: yup.string().optional(),
powerLevel: yup.mixed().oneOf(["low", "medium", "high"]),
});
const joiSchema = Joi.object({
latitude: Joi.number(),
longitude: Joi.number(),
scale: Joi.number().min(5).max(18),
name: Joi.string().optional(),
address: Joi.string().optional(),
powerLevel: Joi.string().valid("low", "medium", "high"),
});
const valibotSchema = valibot.object({
latitude: valibot.number(),
longitude: valibot.number(),
scale: valibot.number([valibot.minRange(5), valibot.maxRange(18)]),
name: valibot.optional(valibot.string()),
address: valibot.optional(valibot.string()),
powerLevel: valibot.enumType(["low", "medium", "high"]),
});
suite
.add("zod validate", () => {
stringSchema.safeParse(value);
})
.add("yup validate", () => {
yupSchema.validate(value);
})
.add("joi validate", () => {
joiSchema.validate(value);
})
.add("valibot validate", () => {
valibot.safeParse(valibotSchema, value);
})
.on("cycle", (e: Benchmark.Event) => {
console.log(`${SUITE_NAME}: ${e.target}`);
})
.on("complete", function () {
console.log("Fastest is " + this.filter("fastest").map("name"));
process.exit(0);
})
.run();
Zod
is so fast, is my case not good or any plan to improve performance?
Hi! Current implementation of branded types uses single symbol for single branded type, that results to never type in tests
valibot/library/src/methods/brand/brand.test.ts
Lines 32 to 38 in ce49b0b
It happends because typescript resolves { [symbol]: "1"} & { [symbol]: "2" }
to never
.
I'll make a pr for fix, that replaces single value to object of values
any plans to make a discord server? i would put that question in discussion but it not available :D
Hello Fabian and the rest of the team, I'm Andreas, the author of the SvelteKit Superforms library. Nice project you've got going! You talked about integrations in your introductory post, it would be very nice to be able to use valibot in Superforms, as I'm planning to support multiple validation libraries in v2.0.
It's not as simple as providing schema validation though, for a complete integration there need to be some schema introspection available. I've started a discussion at typeschema about the requirements: decs/typeschema#9
It would be interesting to hear your thoughts about this. I'm frankly a bit worried that such a basic problem as form validation has become so fragmented, with a dozen libraries doing the same thing differently, instead of focus being on standards.
Introduce brand
method
const BrandType: unique symbol = Symbol()
interface Brand<K extends string | symbol> {
readonly [BrandType]: {
readonly [k in K]: K
}
}
type Branded<T, K extends string | symbol> = T & Brand<K>
function brand<TSchema extends BaseSchema, const K>(
schema: TSchema,
brand: K
): BaseSchema<Input<TSchema>, Branded<Output<TSchema>, K>>{
return schema
}
const schema = brand(number([maxValue(20)]), "UserId");
parse(schema, 123) // number & Brand<"UserId">
Hi, first of all, thanks for Valibot, looks really cool ๐
One feature that I was looking for was Yup's Ensuring a schema matches an existing type, which could look like this in Valibot:
import { type ObjectSchema, email, minLength, object, string } from 'valibot';
type LoginInput = {
email: string;
password: string;
};
// Check that the schema conforms to the `LoginInput` type
const LoginSchema: ObjectSchema<LoginInput> = object({
email: string([email()]),
password: string([minLength(8)]),
});
What do you think of this feature?
Hello
I tried reading the documentation on valibot.dev, but nothing happens when I click on the "Guides" and "API Reference" links.
Google Chrome | 115.0.5790.114ย (Official Build)ย (arm64)
-- | --
Revision | 67277e15806bf7f0307b37cd6f8f29e71b615796-refs/branch-heads/5790_90@{#25}
OS | macOS Version 13.5 (Build 22G74)
JavaScript | V8ย 11.5.150.16
User agent | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36
Add passthrough
method inspired by Zod to allow parse object()
keeping extra props that are present on original input object but not validated through Schema.
This maybe useful if you want to validate/trasform only "a portion of an object" that you receive from/send to and API, but want to keep all the original extra props present in the object that are not specified in object() schema.
PS: some more discussion points:
unwrap
or do you prefer other way to implement it ?object()
implementation adding another overload with an optional strict: boolean
param before error - but to do it I need to change the implementation of getErrorAndPipe
handling 3 params to discriminate boolean, string, Pipe[] ... I don't know if you'll approve/prefer this kind of implementation, maybe the result is more clear because the real nature of passthrough is just an ObjectSchema
that keep the extra params, but don't know if you like it...objectWithExtraProps
that return ObjectSchema but simply use my parse code to keep props...This are all the ideas I came up when implementing it, what's your opinion?
Originally posted by @dmorosinotto in #15 (comment)
I couldn't find anyway to validate that a number is above/below some value or inside a range. Neither for inclusive ranges or exclusive ones.
In Zod this is done with the gt
and lt
for exclusive ranges and gte
and lte
for inclusive ranges. (Zod also has positive
, negative
, nonpositive
and nonnegative
for ranges bounded by 0
).
https://zod.dev/?id=numbers
(It is possible that this feature is already implemented in valibot and I just couldn't find it)
Let's imagine I expect a string "10 ms" on input and want to validate both string and number parts of it, and expect output as number 10
Currently it could be written something like this
transform(string([endsWith(" ms")]), (value) =>
parse(coerce(number([maxValue(20)]), Number), value.split(" ")[0]),
);
Add a third optional argument to transform func as transform output schema or introduce transformAndValidate
method
transform(
string([endsWith(" ms")]),
(value) => value.split(" ")[0],
coerce(number([maxValue(20)]), Number)
);
Not that important, but why do the docs capitalize the names of schema variables?
E.g. why EmailSchema
, not emailSchema
?
Will there a native valibot โ json schema
conversion?
I think this is what missing from zod
(you have to use zod-to-json-schema
, which is a third party package with some known issues)
Whereas in the python ecosystem, pydantic
has native support to generate json schemas from models.
Lovely work so far!
in my case password and confirm password have to be equal but I can't find which method I have to use
Working with dates in javascript is horrible since the support is quite bad, there are libraries that know how to manage dates quite well.
There is a project that integrates a few libraries called date-io, would it be possible to add support to be able to handle the dates of the integrations here instead of working with Date from javascript?
The libraries would be the ones listed here: https://github.com/dmtrKovalenko/date-io/tree/master#projects
I use js-joda
a lot to do operations on dates such as add N day/month/year, date before/after? and the like (to name a few).
Throwing errors is really expensive operation so even if we can make parse
fast for "success" case, "failure" case will be still slow. This means if we use Valibot for server side validation logic, malicious people might be able to attempt DoS by sending "failure" payload.
I created this issue to discuss architectural / philosophical possibility to stop throwing ValiError without compromising other factors such as bundle size and code simplicity.
Hi
May I know how to create a schema to validate an object with hyphen in the key, e.g. X-API-Key
const ApiKeySchema = object({
headers: object({
"X-API-Key": string("API key is missing", [minLength(1)]),
}),
});
Looks great. Congrats with the initial release.
I bet it would be a good idea to add a resolver for react-hook-form - helpful to gain additional traction I think.
Take this object, created with zod:
const ZodProblemDetailsSchema = z.object({
detail: z.string().optional(),
status: z.number().optional(),
title: z.string().optional(),
type: z.string().optional(),
});
When we infer the type of this schema with the z.infer method, we see that all properties are optional
type ZodProblemDetails = {
detail?: string | undefined;
status?: number | undefined;
title?: string | undefined;
type?: string | undefined;
}
I've implemented the same thing with valibot:
const ProblemDetailsSchema = object({
detail: optional(string()),
status: optional(number()),
title: optional(string()),
type: optional(string()),
});
The type inferred with Output gives this:
type ProblemDetails = {
detail: string | undefined;
status: number | undefined;
title: string | undefined;
type: string | undefined;
}
Would it be possible, as zod does, to mark optional properties of an object as optional, and not just possibly undefined?
(Nice work on this library, by the way!)
"Are the types wrong?" tool reports that Node16
/NodeNext
are having issues importing the package
https://arethetypeswrong.github.io/?p=valibot%400.2.0
Bundler
is reported as using fallback condition, this is not ideal and should be fixed as well.
Schema serialization will make this package a good alternative for JSON schema.
Example:
import { serialize, deserialize, parse } from 'valibot';
const serializedLoginSchema = serialize(LoginSchema);
const deserializedLoginSchema = deserialize(serializedLoginSchema);
const parsedData = parse(deserializedLoginSchema, { email: '[email protected]', password: '12345678' })
console.log(parsedData); // { email: '[email protected]', password: '12345678' }
Serialization won't be possible if transform
or any other method that has JS callbacks.
Hi @fabian-hiller, I have an object like this
object({
description: optional(string()),
isActive: optional(useDefault(boolean(), true)),
link: string(),
title: string(),
type: nativeEnum(MenuType),
})
But when I wrap this object with transform or merge --> All properties mark optional, might be this is an expected behavior or a bug ๐ค. Hope you can check this!
Hello there! Awesome project here. I'd really love to try this library out on my Deno projects. Although I may already do so by directly importing the TypeScript files from GitHub itself, it would be great to have them officially published at deno.land/x for better discoverability.
I have a schema like this:
const postSchema = object({
status: optional(enumType(['publish', "future", "draft", "pending", "private", "trash", "auto-draft", "inherit"]))
});
However, this returns a string type. While it does validate this correctly, the typing is not the correct type.
This is not the expected result as 'string' and 'enum' are completely different. If I pass the result.data.status
to an enum type, I get an error because it is a string type, while technically validated.
J
It'd be really nice to see comparative benchmarks with other similar libs and how they compare with valibot.
For my taste the function names are too close to the type names in typescript. I guess zod evaded that by picking a namespace. This choice could really be a bad part of dev experience.
Usually when using zod a common pattern I see is defining a type guard around the safeParse
that would look something like:
type Data = z.infer<typeof dataSchema>
const isData = (input: unknown): input is Data => {
return dataSchema.safeParse(input).success
}
So I would suggest adding something like an is
function directly in the library to fill this function so that users don't have to create these wrapper functions.
For an example let's say you have a React component that listens to messages and if it's a specific type of message then it sets some local state. Without a built in type guard it would look something like this:
const messageDataSchema = object({
eventId: literal('exampleEventId'),
id: string(),
})
type MessageData = Output<typeof messageDataSchema>
const isMessageData = (input: unknown): input is MessageData => {
return safeParse(messageDataSchema, input).success
}
const Component = () => {
const [id, setId] = useState('')
useEffect(() => {
const handler = ({ data }: MessageEvent['data']) => {
if (isMessageData(data)) {
setId(data.id)
}
}
window.addEventListener('message', handler)
return () => {
window.removeEventListener('message', handler)
}
}, [])
}
So we create the schema, infer that to a type, use the type to create a type guard, and then we can use that type guard in our message handler. Alternatively if we have built in type guards we can do:
const messageDataSchema = object({
eventId: literal('exampleEventId'),
id: string(),
})
const Component = () => {
const [id, setId] = useState('')
useEffect(() => {
const handler = ({ data }: MessageEvent['data']) => {
if (is(messageDataSchema, data)) {
setId(data.id)
}
}
window.addEventListener('message', handler)
return () => {
window.removeEventListener('message', handler)
}
}, [])
}
Now we create the schema and use that directly with the type guard which results in less code for the user to write. Of course we could use safeParse
directly and use its return value and be type safe like this:
const messageDataSchema = object({
eventId: literal('exampleEventId'),
id: string(),
})
const Component = () => {
const [id, setId] = useState('')
useEffect(() => {
const handler = ({ data }: MessageEvent['data']) => {
const res = safeParse(messageDataSchema, data)
if (res.success) {
setId(res.data.id)
}
}
window.addEventListener('message', handler)
return () => {
window.removeEventListener('message', handler)
}
}, [])
}
Personally I would prefer following the more standard format of type guards being their own functions as in the first two examples. With the third example, while working without issues, we split our checking over multiple lines and we don't narrow the type of our argument, instead we create a new variable to hold the typed data which I would also argue is not preferred.
Hi and thank you for your time on it
With the simple code below or Playground
Why do types in name
still contain v.ObjectInput
?
import * as v from "valibot"; // 0.74 kB
const loginSchema = v.object({
email: v.string([
v.minLength(1, "Please enter your email."),
v.email("The email address is badly formatted."),
]),
password: v.string([
v.minLength(1, "Please enter your password."),
v.minLength(8, "You password must have 8 characters or more."),
]),
name: v.object({
first: v.string([v.minLength(1, "Please enter your first name.")]),
last: v.string([v.minLength(1, "Please enter your last name.")]),
}),
});
type Login = v.Input<typeof loginSchema>;
// ^?
I think, all examples on documentation should use a wildcard import to easy for the reader and less confusing
hi i have this
export const pollOptions = object({
//WIP we need more
answer: string([minLength(3)]),
id: optional(union([string(), number()])),
order: number()
});
...
pollOptions: array(pollOptions),
...
is there are a way to check pollOptions is min 1 (2 entries) long or do i have to use custom?
thanks
In the recent years it is possible to register an email address with emoji in domain name and main address. Does this library support such interesting input? Or was some specification used as reference to validate the email?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.