lundegaard / lundegaard/validarium

Suggested structure

Open
#35 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
JavaScript
Stars
28
Forks
9
PR merge metrics
No merged PRs in 30d

Description

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

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

No implementation file or test is named in the issue. Start by reviewing the existing validate, validateMany, combineValidate, predicates, and intl integration, then compare them with the proposed factory signatures and null-or-object result shape. Done means the project has agreed on the API direction and documented the chosen validation and message integration.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, react
Domain
frontend, tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
20/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.