Skip to content

Commit c0998f9

Browse files
committed
WIP: Testing display of delayed errors
1 parent fa8e01b commit c0998f9

File tree

11 files changed

+280
-87
lines changed

11 files changed

+280
-87
lines changed

CHANGELOG.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [1.0.0-rc.2]
99

10+
### Fixed
11+
12+
- Async validation works again for custom validators and `superValidate`.
13+
1014
### Added
1115

12-
- `reset` now have an additional `data` option that can be used to re-populate the form with data.
16+
- `reset` now has an additional `data` option that can be used to re-populate the form with data.
1317
- `intProxy`, `numberProxy`, `dateProxy` and `stringProxy` now have an `empty` option, so empty values can be set to `null` or `undefined`.
1418

1519
## [1.0.0-rc.1]
@@ -19,7 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1923
- Explicitly setting a form `id` for multiple forms is not required anymore when using `use:enhance`, unless the forms are using the same schema. An id can be specified in the options or in a hidden form field called `__superform_id`.
2024
- `setError` doesn't handle form-level errors anymore, use refine/superRefine on the schema, or the `message` helper.
2125
- `FieldPath` is gone - the following methods are now using a string accessor like `tags[2].id` instead of an array like `['tags', 2, 'id']`: `validate`, `setError` and all proxy methods (ending with `Proxy`). This also applies to generic components.
22-
- The signature for `allErrors` and `firstError` has changed to `{ path: string[]; messages: string[] }`.
26+
- The signature for `allErrors` and `firstError` has changed to `{ path: string; messages: string[] }`.
2327
- The literal `"any"` is now an allowed value in `step` for constraints.
2428
- Multiple `regex` and `step` is now allowed in a schema. A warning will be emitted by default, that can be turned off.
2529
- The signature for `options.resetForm` has changed to `boolean | () => boolean` (it was async before).

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292
"@sveltejs/adapter-auto": "^2.1.0",
9393
"@sveltejs/kit": "^1.20.0",
9494
"@sveltejs/package": "^2.0.2",
95+
"@types/throttle-debounce": "^5.0.0",
9596
"@typescript-eslint/eslint-plugin": "^5.59.8",
9697
"@typescript-eslint/parser": "^5.59.8",
9798
"devalue": "^4.3.2",
@@ -108,6 +109,7 @@
108109
"svelte-check": "^3.4.3",
109110
"sveltekit-flash-message": "1.0.0-rc.1",
110111
"sveltekit-rate-limiter": "^0.1.8",
112+
"throttle-debounce": "^5.0.0",
111113
"tslib": "^2.5.2",
112114
"typescript": "^5.0.4",
113115
"vite": "^4.3.9",

pnpm-lock.yaml

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/lib/client/formEnhance.ts

Lines changed: 46 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -98,15 +98,8 @@ export function formEnhance<T extends AnyZodObject, M>(
9898
// Using this type in the function argument causes a type recursion error.
9999
const errors = errs as SuperForm<T, M>['errors'];
100100

101-
function validateChange(change: string[]) {
102-
validateField(
103-
change,
104-
options.validators,
105-
options.defaultValidator,
106-
data,
107-
errors,
108-
tainted
109-
);
101+
async function validateChange(change: string[]) {
102+
await validateField(change, options, data, errors, tainted);
110103
}
111104

112105
function timingIssue(el: EventTarget | null) {
@@ -351,30 +344,14 @@ export function formEnhance<T extends AnyZodObject, M>(
351344
if (options.flashMessage) cancelFlash(options);
352345
} else {
353346
// Client validation
354-
let validationResult;
355-
356-
if (options.validators) {
357-
validationResult = await clientValidation(
358-
get(data),
359-
options.validators,
360-
get(formId),
361-
get(constraints)
362-
);
363-
}
364-
365-
if (
366-
options.delayedValidators &&
367-
(!validationResult || validationResult.valid)
368-
) {
369-
validationResult = await clientValidation(
370-
get(data),
371-
options.delayedValidators,
372-
get(formId),
373-
get(constraints)
374-
);
375-
}
347+
const validation = await clientValidation(
348+
options,
349+
get(data),
350+
get(formId),
351+
get(constraints)
352+
);
376353

377-
if (validationResult && !validationResult.valid) {
354+
if (!validation.valid) {
378355
cancel();
379356

380357
const result = {
@@ -383,7 +360,7 @@ export function formEnhance<T extends AnyZodObject, M>(
383360
(typeof options.SPA === 'boolean'
384361
? undefined
385362
: options.SPA?.failStatus) ?? 400,
386-
data: { form: validationResult.validationResult }
363+
data: { form: validation.result }
387364
};
388365

389366
setTimeout(() => validationResponse({ result }), 0);
@@ -590,8 +567,41 @@ export function formEnhance<T extends AnyZodObject, M>(
590567
}
591568

592569
async function clientValidation<T extends AnyZodObject>(
570+
options: FormOptions<T, never>,
571+
checkData: z.infer<T>,
572+
formId: string | undefined,
573+
constraints: Validation<ZodValidation<T>>['constraints']
574+
) {
575+
let validationResult: Awaited<ReturnType<typeof _clientValidation<T>>>;
576+
577+
if (options.validators) {
578+
validationResult = await _clientValidation(
579+
options.validators,
580+
checkData,
581+
formId,
582+
constraints
583+
);
584+
} else {
585+
validationResult = { valid: true as const };
586+
}
587+
588+
if (options.delayedValidators && validationResult.valid) {
589+
validationResult = await _clientValidation(
590+
options.delayedValidators,
591+
checkData,
592+
formId,
593+
constraints
594+
);
595+
}
596+
597+
return validationResult;
598+
}
599+
600+
async function _clientValidation<T extends AnyZodObject>(
601+
validators:
602+
| FormOptions<T, unknown>['validators']
603+
| FormOptions<T, unknown>['delayedValidators'],
593604
checkData: z.infer<T>,
594-
validators: FormOptions<T, unknown>['validators'],
595605
formId: string | undefined,
596606
constraints: Validation<ZodValidation<T>>['constraints']
597607
) {
@@ -678,7 +688,7 @@ async function clientValidation<T extends AnyZodObject>(
678688

679689
if (valid) return { valid: true as const };
680690

681-
const validationResult: Validation<T> = {
691+
const result: Validation<T> = {
682692
valid,
683693
errors: clientErrors,
684694
data: checkData,
@@ -688,5 +698,5 @@ async function clientValidation<T extends AnyZodObject>(
688698
id: formId
689699
};
690700

691-
return { valid: false as const, validationResult };
701+
return { valid: false as const, result };
692702
}

src/lib/client/index.ts

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,11 @@ export type FormOptions<T extends ZodValidation<AnyZodObject>, M> = Partial<{
107107
}) => MaybePromise<unknown | void>);
108108
dataType: 'form' | 'json';
109109
jsonChunkSize: number;
110-
validators: false | Validators<UnwrapEffects<T>> | T;
111-
delayedValidators: Validators<UnwrapEffects<T>> | T;
110+
validators:
111+
| false
112+
| Validators<UnwrapEffects<T>>
113+
| ZodValidation<UnwrapEffects<T>>;
114+
delayedValidators: Validators<UnwrapEffects<T>>;
112115
validationMethod: 'auto' | 'oninput' | 'onblur' | 'submit-only';
113116
defaultValidator: 'keep' | 'clear';
114117
clearOnSubmit: 'errors' | 'message' | 'errors-and-message' | 'none';
@@ -587,7 +590,7 @@ export function superForm<
587590
return obj === true;
588591
}
589592

590-
function Tainted__validate(path: string[], taint: TaintOption) {
593+
async function Tainted__validate(path: string[], taint: TaintOption) {
591594
if (
592595
options.validationMethod == 'onblur' ||
593596
options.validationMethod == 'submit-only'
@@ -625,15 +628,7 @@ export function superForm<
625628
}
626629

627630
if (shouldValidate) {
628-
validateField(
629-
path,
630-
options.validators,
631-
options.defaultValidator,
632-
Form,
633-
Errors,
634-
Tainted,
635-
{ taint }
636-
);
631+
await validateField(path, options, Form, Errors, Tainted, { taint });
637632
}
638633
}
639634

@@ -860,8 +855,7 @@ export function superForm<
860855
validate: (path, opts) => {
861856
return validateField(
862857
splitPath(path) as string[],
863-
options.validators,
864-
options.defaultValidator,
858+
options,
865859
Form,
866860
Errors,
867861
Tainted,

0 commit comments

Comments
 (0)