Skip to content

Commit

Permalink
fix: renamed properties, ajusted tests and zod types
Browse files Browse the repository at this point in the history
  • Loading branch information
victorgarciaesgi committed Dec 9, 2024
1 parent f7d3474 commit 0e419dd
Show file tree
Hide file tree
Showing 14 changed files with 142 additions and 108 deletions.
7 changes: 6 additions & 1 deletion docs/src/core-concepts/validation-properties.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,14 +146,19 @@ To know more about the rule properties check the [rules properties section](/cor
## Specific properties for nested objects

### `$fields`
- Type: `Record<string, RegleStatu | RegleFieldStatus | RegleCollectionStatus>`
- Type: `Record<string, RegleStatus | RegleFieldStatus | RegleCollectionStatus>`

This represents all the children of your object. You can access any nested child at any depth to get the relevant data you need for your form.


## Specific properties for collections
- Type: `Array<string, RegleStatus>`


### `$each`

This will store the status of every item in your collection. Each item will be a classic field you can access, or map on it to display your elements.

### `$field`

Represent the status of the collection itself. You can have validations on the array like `minLength`, this field represent the isolated status of the collection.
Original file line number Diff line number Diff line change
@@ -1,29 +1,22 @@
import type { RequiredDeep } from 'type-fest';
import type { ComputedRef, EffectScope, Ref, ToRefs, WatchStopHandle } from 'vue';
import { computed, effectScope, reactive, ref, toRaw, toRef, watch, watchEffect } from 'vue';
import { computed, effectScope, reactive, ref, toRef, watch, watchEffect } from 'vue';
import { isEmpty } from '../../../../../../shared';
import type {
$InternalFormPropertyTypes,
$InternalRegleCollectionErrors,
$InternalRegleCollectionRuleDecl,
$InternalRegleCollectionStatus,
$InternalRegleErrors,
$InternalRegleFieldStatus,
$InternalRegleResult,
$InternalRegleStatusType,
CustomRulesDeclarationTree,
DeepMaybeRef,
RegleBehaviourOptions,
RegleCollectionRuleDeclKeyProperty,
RegleShortcutDefinition,
ResolvedRegleBehaviourOptions,
} from '../../../../types';
import { cloneDeep, isObject, randomId, resetArrayValuesRecursively, unwrapGetter } from '../../../../utils';
import { isVueSuperiorOrEqualTo3dotFive } from '../../../../utils/version-compare';
import type { RegleStorage } from '../../../useStorage';
import { isNestedRulesStatus, isRuleDef } from '../../guards';
import { createReactiveFieldStatus } from './../createReactiveFieldStatus';
import { isEmpty } from '../../../../../../shared';
import type { StateWithId } from '../common/common-types';
import { createReactiveFieldStatus } from './../createReactiveFieldStatus';
import { createCollectionElement } from './createReactiveCollectionElement';

interface CreateReactiveCollectionStatusArgs {
Expand Down Expand Up @@ -170,7 +163,7 @@ export function createReactiveCollectionStatus({
path,
storage,
options,
externalErrors: toRef(externalErrors?.value ?? {}, `$errors`),
externalErrors: toRef(externalErrors?.value ?? {}, `$self`),
$isArray: true,
initialState: initialState,
shortcuts,
Expand Down Expand Up @@ -299,18 +292,18 @@ export function createReactiveCollectionStatus({
);
});

const $errors = computed<$InternalRegleCollectionErrors>(() => {
const $errors = computed(() => {
return {
$errors: $fieldStatus.value.$errors,
$self: $fieldStatus.value.$errors,
$each: $eachStatus.value.map(($each) => $each.$errors),
};
} satisfies $InternalRegleCollectionErrors;
});

const $silentErrors = computed<$InternalRegleCollectionErrors>(() => {
const $silentErrors = computed(() => {
return {
$errors: $fieldStatus.value.$silentErrors,
$self: $fieldStatus.value.$silentErrors,
$each: $eachStatus.value.map(($each) => $each.$silentErrors),
};
} satisfies $InternalRegleCollectionErrors;
});

const $name = computed(() => fieldName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ export function createReactiveNestedStatus({
});

const $error = computed<boolean>(() => {
return $dirty.value && !$pending.value && $invalid.value;
return $anyDirty.value && !$pending.value && $invalid.value;
});

const $ready = computed<boolean>(() => {
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/types/rules/rule.errors.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ export type RegleValidationErrors<TState extends Record<string, any> | any[] | u
: string[];

export type RegleCollectionErrors<TState extends Record<string, any>> = {
readonly $errors: string[];
readonly $self: string[];
readonly $each: RegleValidationErrors<TState>[];
};

/** @internal */
export type $InternalRegleCollectionErrors = {
readonly $errors?: string[];
readonly $self?: string[];
readonly $each?: $InternalRegleErrors[];
};

Expand Down
6 changes: 5 additions & 1 deletion packages/zod/src/types/core.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,15 +65,19 @@ export interface ZodRegleFieldStatus<
[Key in `${string & TSchema['_def']['typeName']}`]: RegleRuleStatus<TState[TKey], []>;
};
$validate: () => Promise<false | z.output<TSchema>>;
$extractDirtyFields: (filterNullishValues?: boolean) => PartialDeep<TState>;
}

/**
* @public
*/
export interface ZodRegleCollectionStatus<TSchema extends z.ZodTypeAny, TState extends any[]>
extends Omit<ZodRegleFieldStatus<TSchema, TState>, '$errors' | '$silentErrors'> {
extends Omit<ZodRegleFieldStatus<TSchema, TState>, '$errors' | '$silentErrors' | '$value'> {
$value: TState;
readonly $each: Array<InferZodRegleStatusType<NonNullable<TSchema>, TState, number>>;
readonly $field: ZodRegleFieldStatus<TSchema, TState>;
readonly $errors: ZodToRegleCollectionErrors<TSchema>;
readonly $silentErrors: ZodToRegleCollectionErrors<TSchema>;
$extractDirtyFields: (filterNullishValues?: boolean) => PartialDeep<TState>;
$validate: () => Promise<false | z.output<TSchema>>;
}
2 changes: 1 addition & 1 deletion packages/zod/src/types/errors.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ export type ZodDefToRegleValidationErrors<TRule extends z.ZodTypeAny> =
: string[];

export type ZodToRegleCollectionErrors<TRule extends z.ZodTypeAny> = {
readonly $errors: string[];
readonly $self: string[];
readonly $each: ZodDefToRegleValidationErrors<TRule>[];
};
68 changes: 63 additions & 5 deletions tests/unit/useRegle/errors/errorsMessages.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { defineRegleConfig, useRegle } from '@regle/core';
import { createRule, defineRegleConfig, useRegle } from '@regle/core';
import { withMessage } from '@regle/rules';
import { ref } from 'vue';
import { createRegleComponent } from '../../../utils/test.utils';
Expand All @@ -15,22 +15,54 @@ function errorsRules() {
() => ['Error 2.1', 'Error 2.2']
);

const createRuleOneError = createRule({ validator: () => false, message: 'Error 3' });
const createRuleMultipleError = createRule({
validator: () => false,
message: ['Error 3.1', 'Error 3.2', 'Error 3.3'],
});
const createRuleFunctionOneError = createRule({ validator: () => false, message: () => 'Error 4' });
const createRuleFunctionMultipleError = createRule({ validator: () => false, message: () => ['Error 4.1'] });

const allValidators = {
ruleWithOneError,
ruleWithMultipleErrors,
ruleFunctionWithOneError,
ruleFunctionWithMultipleError,
createRuleOneError,
createRuleMultipleError,
createRuleFunctionOneError,
createRuleFunctionMultipleError,
};

const form = ref({
email: '',
user: {
firstName: '',
nested: {
child: '',
collection: [{ name: '' }],
},
},
contacts: [{ name: '' }],
});

return useRegle(form, {
email: { ruleWithOneError, ruleWithMultipleErrors, ruleFunctionWithOneError, ruleFunctionWithMultipleError },
email: allValidators,
user: {
firstName: { ruleWithOneError, ruleWithMultipleErrors, ruleFunctionWithOneError, ruleFunctionWithMultipleError },
firstName: allValidators,
nested: {
child: allValidators,
collection: {
...allValidators,
$each: {
name: allValidators,
},
},
},
},
contacts: {
$each: {
name: { ruleWithOneError, ruleWithMultipleErrors, ruleFunctionWithOneError, ruleFunctionWithMultipleError },
name: allValidators,
},
},
});
Expand All @@ -43,10 +75,36 @@ describe('errors', () => {
vm.r$.$touch();
await vm.$nextTick();

const expectedErrors = ['Error', 'Error 1.1', 'Error 1.2', 'Error 2', 'Error 2.1', 'Error 2.2'];
const expectedErrors = [
'Error',
'Error 1.1',
'Error 1.2',
'Error 2',
'Error 2.1',
'Error 2.2',
'Error 3',
'Error 3.1',
'Error 3.2',
'Error 3.3',
'Error 4',
'Error 4.1',
];

expect(vm.r$.$fields.email.$errors).toStrictEqual(expectedErrors);
expect(vm.r$.$fields.user.$fields.firstName.$errors).toStrictEqual(expectedErrors);
expect(vm.r$.$fields.user.$fields.nested.$fields.child.$errors).toStrictEqual(expectedErrors);
expect(vm.r$.$fields.user.$fields.nested.$fields.collection.$field.$errors).toStrictEqual(expectedErrors);
expect(vm.r$.$fields.user.$fields.nested.$fields.collection.$errors.$self).toStrictEqual(expectedErrors);
expect(vm.r$.$fields.user.$fields.nested.$fields.collection.$each[0].$fields.name.$errors).toStrictEqual(
expectedErrors
);
expect(vm.r$.$fields.contacts.$each[0].$fields.name.$errors).toStrictEqual(expectedErrors);

vm.r$.$value.contacts.push({ name: '' });
await vm.$nextTick();
vm.r$.$touch();
await vm.$nextTick();

expect(vm.r$.$fields.contacts.$each[1].$fields.name.$errors).toStrictEqual(expectedErrors);
});
});
6 changes: 3 additions & 3 deletions tests/unit/useRegle/properties/$errors.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ describe('$silentErrors', () => {
name: [],
},
],
$errors: [],
$self: [],
},
email: [],
user: {
Expand All @@ -33,7 +33,7 @@ describe('$silentErrors', () => {
name: ['This field is required'],
},
],
$errors: [],
$self: [],
},
email: ['This field is required'],
user: {
Expand All @@ -55,7 +55,7 @@ describe('$silentErrors', () => {
name: ['This field is required'],
},
],
$errors: [],
$self: [],
},
email: ['Value must be an valid email address'],
user: {
Expand Down
37 changes: 10 additions & 27 deletions tests/unit/useRegle/properties/$params.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,7 @@ describe('$params', () => {
contacts: {
$each: {
name: {
testParams: withParams(
(value: Maybe<string>, min) => (value?.length ?? 0) > min,
[min]
),
testParams: withParams((value: Maybe<string>, min) => (value?.length ?? 0) > min, [min]),
},
},
},
Expand Down Expand Up @@ -114,36 +111,30 @@ describe('$params', () => {

expect(vm.r$.$fields.email.$rules.testParams.$params).toStrictEqual([6]);
expect(vm.r$.$fields.user.$fields.firstName.$rules.testParams.$params).toStrictEqual([6]);
expect(vm.r$.$fields.contacts.$each[0].$fields.name.$rules.testParams.$params).toStrictEqual([
6,
]);
expect(vm.r$.$fields.contacts.$each[0].$fields.name.$rules.testParams.$params).toStrictEqual([6]);

vm.r$.$value.contacts.push({ name: '' });
await nextTick();

vm.min = 10;
await nextTick();

shouldBeInvalidField(vm.r$);
shouldBeErrorField(vm.r$);
shouldBeErrorField(vm.r$.$fields.email);
shouldBeErrorField(vm.r$.$fields.user.$fields.firstName);
shouldBeErrorField(vm.r$.$fields.contacts.$each[0].$fields.name);
shouldBeInvalidField(vm.r$.$fields.contacts.$each[1].$fields.name);

expect(vm.r$.$fields.email.$rules.testParams.$params).toStrictEqual([10]);
expect(vm.r$.$fields.user.$fields.firstName.$rules.testParams.$params).toStrictEqual([10]);
expect(vm.r$.$fields.contacts.$each[0].$fields.name.$rules.testParams.$params).toStrictEqual([
10,
]);
expect(vm.r$.$fields.contacts.$each[1].$fields.name.$rules.testParams.$params).toStrictEqual([
10,
]);
expect(vm.r$.$fields.contacts.$each[0].$fields.name.$rules.testParams.$params).toStrictEqual([10]);
expect(vm.r$.$fields.contacts.$each[1].$fields.name.$rules.testParams.$params).toStrictEqual([10]);

vm.min = 5;

await nextTick();

shouldBeInvalidField(vm.r$);
shouldBeErrorField(vm.r$);
shouldBeValidField(vm.r$.$fields.email);
shouldBeCorrectNestedStatus(vm.r$.$fields.user);
shouldBeValidField(vm.r$.$fields.user.$fields.firstName);
Expand All @@ -153,12 +144,8 @@ describe('$params', () => {

expect(vm.r$.$fields.email.$rules.testParams.$params).toStrictEqual([5]);
expect(vm.r$.$fields.user.$fields.firstName.$rules.testParams.$params).toStrictEqual([5]);
expect(vm.r$.$fields.contacts.$each[0].$fields.name.$rules.testParams.$params).toStrictEqual([
5,
]);
expect(vm.r$.$fields.contacts.$each[1].$fields.name.$rules.testParams.$params).toStrictEqual([
5,
]);
expect(vm.r$.$fields.contacts.$each[0].$fields.name.$rules.testParams.$params).toStrictEqual([5]);
expect(vm.r$.$fields.contacts.$each[1].$fields.name.$rules.testParams.$params).toStrictEqual([5]);

vm.r$.$value.contacts[1].name = 'aeeyeziyr';
await nextTick();
Expand Down Expand Up @@ -311,9 +298,7 @@ describe('$params', () => {

expect(vm.r$.$fields.email.$rules.testParams.$params).toStrictEqual([6]);
expect(vm.r$.$fields.user.$fields.firstName.$rules.testParams.$params).toStrictEqual([6]);
expect(vm.r$.$fields.contacts.$each[0].$fields.name.$rules.testParams.$params).toStrictEqual([
6,
]);
expect(vm.r$.$fields.contacts.$each[0].$fields.name.$rules.testParams.$params).toStrictEqual([6]);

vm.min = 20;

Expand All @@ -338,9 +323,7 @@ describe('$params', () => {

expect(vm.r$.$fields.email.$rules.testParams.$params).toStrictEqual([20]);
expect(vm.r$.$fields.user.$fields.firstName.$rules.testParams.$params).toStrictEqual([20]);
expect(vm.r$.$fields.contacts.$each[0].$fields.name.$rules.testParams.$params).toStrictEqual([
20,
]);
expect(vm.r$.$fields.contacts.$each[0].$fields.name.$rules.testParams.$params).toStrictEqual([20]);
});
});
});
14 changes: 4 additions & 10 deletions tests/unit/useRegle/properties/$silentErrors.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ describe('$silentErrors', () => {
name: ['This field is required'],
},
],
$errors: [],
$self: [],
},
email: ['This field is required', 'Value must be an valid email address'],
user: {
Expand All @@ -21,18 +21,12 @@ describe('$silentErrors', () => {
},
});

expect(vm.r$.$fields.contacts.$each[0].$fields.name.$silentErrors).toStrictEqual([
'This field is required',
]);
expect(vm.r$.$fields.contacts.$each[0].$fields.name.$silentErrors).toStrictEqual(['This field is required']);
expect(vm.r$.$fields.email.$silentErrors).toStrictEqual([
'This field is required',
'Value must be an valid email address',
]);
expect(vm.r$.$fields.user.$fields.firstName.$silentErrors).toStrictEqual([
'This field is required',
]);
expect(vm.r$.$fields.user.$fields.lastName.$silentErrors).toStrictEqual([
'This field is required',
]);
expect(vm.r$.$fields.user.$fields.firstName.$silentErrors).toStrictEqual(['This field is required']);
expect(vm.r$.$fields.user.$fields.lastName.$silentErrors).toStrictEqual(['This field is required']);
});
});
Loading

0 comments on commit 0e419dd

Please sign in to comment.