lundegaard / validarium Goto Github PK
View Code? Open in Web Editor NEW🛡Agnostic validation library for JavaScript applications.
Home Page: https://validarium.js.org
License: MIT License
🛡Agnostic validation library for JavaScript applications.
Home Page: https://validarium.js.org
License: MIT License
src/index.js only exports translateMessage as default
I think it would be useful to have conditional validations. Like
validate({
firstName: { validations: [isRequired, ...], conditions: [isUserPresent, ...]},
})
conditions should get all form values.
Or we can make condition part of validation itself if we extend the API.
Currently they reference nonexistent validarium-validations.js file
validateMany
currently returns an array of results ([null]
), even if all subvalidations successfully pass. null
should be returned directly to be consistent with validate
and allow nesting of validate
and validateMany
calls.
validate({
foo: [isRequired]
})({
foo: 'bar'
}); // === null
validateMany({
foo: [isRequired]
})([{
foo: 'bar'
}]) // === [null], expected to be null
validate({
arr: [
validateMany({
foo: [isRequired]
})
]
})({
arr: [{
foo: 'bar'
}]
}) // === {arr: [null]}, expected to be null
Of course when at least one validation fails, the structure should be kept as is to know which index is wrong.
Proposed fix:
const fixedValidateMany = validations => o(when(all(isNil), always(null)), validateMany(validations));
Make this library truly agnostic
PS. Don't forget to add agnostic
into readme.
Right now there are just a few validations that are not even categorized.
I think it would be useful to have nested objects validations. Like
validate({
user: {
email: [isRequired, isEmail, hasLengthMax(200)],
age: [isRequired, isNumber, hasValueMin(18)],
}
})
We can already translate this type of validation results by intl translator. But we are not able to validate them.
There seems to be bug in https://github.com/lundegaard/validarium/blob/master/packages/validations/src/hasLengthMin.js
More specifically the implementation counts with message key minLength that is passed to createValidation function. But this message key is not present in imported message object m.
I believe the m.hasLengthMin should be passed to createValidation function.
@validarium/domain-cs
package@validarium/domain-cs
although line [isIntlMessageWithArgs, ({ message, messageValues }) => formatMessage(message, messageValues)],
should technically support it, pickByNotNil
ruins everything :(
The documentation for isRequired
states
Checks if the value is present
The current implementation however does not only check if the value is present, but also checks if the value is truthy
This is confusing, because valid values, such as 0
, are resolved as invalid. I think 0
is a perfectly reasonable value for a "required" numerical input or select box. The same applies to boolean values - the validation should force the user to "make a choice", not to "pick true
"
Currently these validations are present, but not exported. Therefore they cannot be used.
I think that it would be useful to have something like that:
validate({
users: [{
email: [isRequired, isEmail, hasLengthMax(200)],
age: [isRequired, isNumber, hasValueMin(18)],
}]
});
or
validate({
users: validateMany({
email: [isRequired, isEmail, hasLengthMax(200)],
age: [isRequired, isNumber, hasValueMin(18)],
})
});
but it should be also possible to validate array itself. Like users: [isGreatenThan10, isRequired, ...]
... and use it in validation
package.
Hi @tommmyy, in our internal project, I sketched a draft of what validarium could look like in terms of predicates, validations and integration with intl. I'm creating this issue so that the suggestion is written down somewhere and not just forgotten in the git history.
First of all, validate
, validateMany
and combineValidate
are fine and I don't think any changes are necessary in this regard. However, what users of validarium often don't realise is that if you need to do validations using multiple fields, validate
shouldn't/cannot be used.
Although the library should technically be agnostic (which should be possible). I think the APIs should suit the libraries that we use in our stack: redux-form and react-intl. There do not have to be any dependencies on these libraries I think.
Because we don't use the intl
package in our internal project, this package should just be removed.
Predicates should always be factories, meaning that even a simple isRequired
predicate needs to be "initialized":
validate({ name: [isRequired()] })
This allows validations (or validators, however we want to call this concept) to be created dynamically. Here's a sketch:
import { o, pick, keys, mapObjIndexed } from 'ramda';
import createValidation from './createValidation';
import * as predicates from './predicates';
import messages from './messages';
const validations = o(
mapObjIndexed((predicate, key) => (options, message = messages[key]) =>
createValidation(predicate, message, options)
),
pick(keys(predicates)) // NOTE: To only select enumerable properties.
)(predicates);
export default validations;
and
import { cond, T } from 'ramda';
import { alwaysNull } from 'ramda-extension';
const createValidation = (predicate, message, options) =>
cond([
// TODO: Add null safety?
[predicate(options), alwaysNull],
[T, value => ({ value, message, options })],
]);
export default createValidation;
This allows the following usage:
import v from '@validarium/validations'
v.isRequired()
v.hasLengthMax({ max: 100 })
v.hasLengthMax({ max: 100 }, { id: 'sth', defaultMessage: 'Max length is {max}' })
Meaning that we can easily override validation messages and the creation process of validations is also simplified.
It is possible to further optimize this by creating the validations as a build script (allowing for code completion and better imports), but the predicate structure should stay consistent.
Validations either return null
(if validation passed) or they return { value, message, options }
object. With redux-form, this object should be stored as the field error (storing the translated value doesn't make much sense).
When visualising the error, this should be handled by a decorator/hook aware of both react-intl
and redux-form
. We could provide one in this library as a separate package, although a simple recipe would probably do.
Signatures:
Predicate
(options?: Object) => (value: any) => bool
Validation
(options?: Object, message?: Message) =>
(value: any) =>
({ message: Message, options?: Object, value: any }) || null
Because of the {9}
segment, this predicate is useless outside the Czech Republic and possibly some other countries :(
It would be useful to have async validations based on Promises since it is the most convenient JS solution.
IMO this package should really just be 2 files: messages and something that loops over all predicates and connects them with the message. This should be possible if we choose a convention for the values passed to messages, e.g. $1
, $2
or so (or by always passing objects).
@validarium/predicates should contain all predicate functions that are used by validations in @validarium/intl
packages. Right now they are hard-coded within validation itself.
in messages keys hasAgeInInterval and matches has same message id.
hasAgeInInterval: { id: 'validarium.hasAgeInInterval', defaultMessage: 'You must be between {minAge} and {maxAge} years old', }, matches: { id: 'validarium.hasAgeInInterval', defaultMessage: 'Value has a wrong format', },
All validations should be optional and null safe. Required fields should be explicitly marked with isRequired
validations. Otherwise, we have no other choice than duplicate every validation and make it optional.
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.