Skip to content

Commit

Permalink
feat: added date validators
Browse files Browse the repository at this point in the history
  • Loading branch information
victorgarciaesgi committed Nov 7, 2023
1 parent 699dd5a commit 9f75e9a
Show file tree
Hide file tree
Showing 19 changed files with 139 additions and 24 deletions.
34 changes: 18 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,22 @@ It's heavily inspired by Vuelidate.
> API or function names can still change

# Improvements from Vuelidate

- 100% type safety
- Made for Vue 3 and composition API first
- Collection validation ($each is back without performance issues)
- Global config
- External results improvements
- Async rules with params
- Easier rule declaration
- Performances (need benchmark)

# What is still missing from Vuelidate

- Validation groups


# Documentation

TODO
Expand All @@ -35,21 +51,7 @@ TODO
- Nuxt 3
- Pinia

# What I upgraded from Vuelidate

- 100% type safety
- Made for Vue 3 and composition API first
- Collection validation ($each is back without performance issues)
- Global config
- External results improvements
- Async rules with params
- Easier rule declaration
- Performances (need benchmark)


# What is still missing from Vuelidate

- Validation groups


# Roadmap
Expand All @@ -65,8 +67,8 @@ TODO
- [x] Regex helper
- [x] Additional rules and "and" helper
- [x] "or" and "not" helper
- [ ] withExternalErrors
- [ ] Dates built-in validators
- [x] externalErrors
- [x] Dates built-in validators
- [ ] Zod support
- [ ] Nested component collection (? need poll)
- [ ] Unit tests
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/core/defaultValidators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ export type DefaultValidators = {
requireUnless: RegleRuleWithParamsDefinition<unknown, [condition: boolean]>;
sameAs: RegleRuleWithParamsDefinition<unknown, [target: unknown]>;
url: RegleRuleDefinition<string>;
dateAfter: RegleRuleWithParamsDefinition<Date, [after: Date]>;
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { RequiredDeep } from 'type-fest';
import { ComputedRef, Ref, computed, nextTick, reactive, ref, toRef, toRefs, watch } from 'vue';
import { Ref, nextTick, reactive, ref, toRef, toRefs, watch } from 'vue';
import type {
$InternalExternalRegleErrors,
$InternalFormPropertyTypes,
Expand All @@ -9,16 +9,14 @@ import type {
$InternalRegleStatusType,
CustomRulesDeclarationTree,
RegleBehaviourOptions,
RegleExternalCollectionErrors,
RegleExternalErrorTree,
ResolvedRegleBehaviourOptions,
} from '../../../types';
import { DeepMaybeRef } from '../../../types';
import { randomId } from '../../../utils/randomId';
import { RegleStorage } from '../../useStorage';
import { isExternalErrorCollection } from '../guards';
import { createReactiveFieldStatus } from './createReactiveFieldStatus';
import { createReactiveChildrenStatus } from './createReactiveNestedStatus';
import { isExternalErrorCollection } from '../guards';

function createCollectionElement({
path,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@ export function createReactiveFieldStatus({
$commit();
}
$externalErrors.value = [];
console.log($externalErrors.value);
});

function $unwatch() {
Expand Down
2 changes: 1 addition & 1 deletion packages/validators/src/helpers/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export { withMessage } from './withMessage';
export { withAsync } from './withAsync';
export { applyIf } from './applyIf';
export { ruleHelpers } from './rulesHelpers';
export { ruleHelpers } from './ruleHelpers';
export { and } from './and';
export { or } from './or';
export { not } from './not';
2 changes: 1 addition & 1 deletion packages/validators/src/helpers/not.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
RegleRuleDefinitionProcessor,
createRule,
} from '@regle/core';
import { ruleHelpers } from './rulesHelpers';
import { ruleHelpers } from './ruleHelpers';

export function not<TValue, TParams extends any[] = any[]>(
rule: FormRuleDeclaration<TValue, TParams>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@ import { isFilled } from './isFilled';
import { isNumber } from './isNumber';
import { regex } from './regex';
import { size } from './size';
import { isDate } from './isDate';
import { toDate } from './toDate';

export const ruleHelpers = {
isEmpty,
isFilled,
size,
regex,
isNumber,
isDate,
toDate,
};
24 changes: 24 additions & 0 deletions packages/validators/src/helpers/ruleHelpers/isDate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { isEmpty } from './isEmpty';

export function isDate(value: unknown): value is Date {
if (isEmpty(value)) {
return false;
}
try {
let possibleDate: Date | null = null;
if (value instanceof Date) {
possibleDate = value;
} else if (typeof value === 'number' && !isNaN(value)) {
possibleDate = new Date(value);
} else if (typeof value === 'string') {
const date = new Date(value);
if (date.toString() === 'Invalid Date') {
return false;
}
possibleDate = date;
}
return !!possibleDate;
} catch (e) {
return false;
}
}
12 changes: 12 additions & 0 deletions packages/validators/src/helpers/ruleHelpers/toDate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export function toDate(argument: Date) {
const argStr = Object.prototype.toString.call(argument);
if (argument instanceof Date || (typeof argument === 'object' && argStr === '[object Date]')) {
return new Date(argument.getTime());
} else if (typeof argument === 'number' || argStr === '[object Number]') {
return new Date(argument);
} else if (typeof argument === 'string' || argStr === '[object String]') {
return new Date(argument);
} else {
return new Date(NaN);
}
}
18 changes: 18 additions & 0 deletions packages/validators/src/validators/dateAfter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { ruleHelpers } from '../helpers';
import { createRule, Maybe, RegleRuleWithParamsDefinition } from '@regle/core';

export const dateAfter: RegleRuleWithParamsDefinition<Date, [after: Maybe<Date>]> = createRule<
Date,
[after: Maybe<Date>]
>({
validator: (value, after) => {
if (ruleHelpers.isDate(value) && ruleHelpers.isDate(after)) {
return ruleHelpers.toDate(value).getTime() > ruleHelpers.toDate(after).getTime();
}
return true;
},
message: (_, after) => {
return `The date must be after ${after}`;
},
type: 'dateAfter',
});
18 changes: 18 additions & 0 deletions packages/validators/src/validators/dateBefore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { ruleHelpers } from '../helpers';
import { createRule, Maybe, RegleRuleWithParamsDefinition } from '@regle/core';

export const dateBefore: RegleRuleWithParamsDefinition<Date, [before: Maybe<Date>]> = createRule<
Date,
[before: Maybe<Date>]
>({
validator: (value, before) => {
if (ruleHelpers.isDate(value) && ruleHelpers.isDate(before)) {
return ruleHelpers.toDate(value).getTime() < ruleHelpers.toDate(before).getTime();
}
return true;
},
message: (_, before) => {
return `The date must be before ${before}`;
},
type: 'dateBefore',
});
18 changes: 18 additions & 0 deletions packages/validators/src/validators/dateBetween.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { ruleHelpers } from '../helpers';
import { createRule, Maybe, RegleRuleWithParamsDefinition } from '@regle/core';

export const dateBetween: RegleRuleWithParamsDefinition<
Date,
[before: Maybe<Date>, after: Maybe<Date>]
> = createRule<Date, [before: Maybe<Date>, after: Maybe<Date>]>({
validator: (value, after) => {
if (ruleHelpers.isDate(value) && ruleHelpers.isDate(after)) {
return ruleHelpers.toDate(value).getTime() < ruleHelpers.toDate(after).getTime();
}
return true;
},
message: (_, after) => {
return `The date must be before ${after}`;
},
type: 'dateBetween',
});
3 changes: 3 additions & 0 deletions packages/validators/src/validators/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@ export * from './required';
export * from './requiredUnless';
export * from './sameAs';
export * from './url';
export * from './dateAfter';
export * from './dateBefore';
export * from './dateBetween';
20 changes: 19 additions & 1 deletion playground/vue3/src/components/MyForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@
<li v-for="error of $errors.firstName" :key="error">{{ error }}</li>
</ul>

<input type="date" v-model="form.birthDate" placeholder="Birth date" />
<ul>
<li v-for="error of $errors.birthDate" :key="error">{{ error }}</li>
</ul>

<input type="date" v-model="form.today" placeholder="Today" />
<ul>
<li v-for="error of $errors.today" :key="error">{{ error }}</li>
</ul>

<template :key="index" v-for="(input, index) of form.foo.bloublou.test">
<input v-model="input.name" placeholder="name" />
<ul>
Expand Down Expand Up @@ -50,6 +60,7 @@ import {
minLength,
not,
sameAs,
dateAfter,
} from '@regle/validators';
import { reactive, ref, watch } from 'vue';
import { asyncEmail, useRegle } from './../validations';
Expand All @@ -59,6 +70,8 @@ import { RegleExternalErrorTree } from '@regle/core';
type Form = {
email?: string;
firstName?: number;
birthDate?: Date;
today?: Date;
foo: {
bar?: number | undefined;
bloublou: {
Expand All @@ -71,7 +84,6 @@ type Form = {
const form = reactive<Form>({
email: '',
firstName: undefined,
foo: {
bar: 5,
bloublou: {
Expand Down Expand Up @@ -109,6 +121,12 @@ const { $regle, $errors, validateForm, $state } = useRegle(
'Should not be same as email'
),
},
birthDate: {
required,
},
today: {
dateAfter: dateAfter(() => form.birthDate),
},
foo: {
bloublou: {
test: {
Expand Down

0 comments on commit 9f75e9a

Please sign in to comment.