Skip to content

Commit f158f94

Browse files
committed
Added custom fail function.
Added result to onUpdate event.
1 parent 6c4ad73 commit f158f94

File tree

10 files changed

+137
-7
lines changed

10 files changed

+137
-7
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ Headlines: Added, Changed, Deprecated, Removed, Fixed, Security
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [Unreleased]
9+
10+
### Added
11+
12+
- The `ActionResult` for success or failure is now added to the `onUpdate` event in the `result` property.
13+
- Added a `fail` function, works the same as the SvelteKit fail, but removes files and sets `form.valid` to `false`.
14+
815
## [2.10.6] - 2024-03-20
916

1017
### Changed

src/lib/client/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export {
3535
setError,
3636
withFiles,
3737
removeFiles,
38+
fail,
3839
type SuperValidated,
3940
type TaintedFields,
4041
type ValidationErrors

src/lib/client/superForm.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ export type FormOptions<
118118
formEl: HTMLFormElement;
119119
formElement: HTMLFormElement;
120120
cancel: () => void;
121+
result: Extract<ActionResult, { type: 'success' | 'failure' }>;
121122
}) => MaybePromise<unknown | void>;
122123
onUpdated: (event: { form: Readonly<SuperValidated<T, M, In>> }) => MaybePromise<unknown | void>;
123124
onError:
@@ -1791,13 +1792,17 @@ export function superForm<
17911792
form: newForm as SuperValidated<T, M, In>,
17921793
formEl: FormElement,
17931794
formElement: FormElement,
1794-
cancel: () => (cancelled = true)
1795+
cancel: () => (cancelled = true),
1796+
result: result as Extract<ActionResult, { type: 'success' | 'failure' }>
17951797
};
17961798

17971799
for (const event of formEvents.onUpdate) {
17981800
await event(data);
17991801
}
18001802

1803+
// In case it was modified in the event
1804+
result = data.result as ActionResult;
1805+
18011806
if (!cancelled) {
18021807
if (options.customValidity) {
18031808
setCustomValidityForm(FormElement, data.form.errors);

src/lib/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export {
3131
setError,
3232
withFiles,
3333
removeFiles,
34+
fail,
3435
type SuperValidated,
3536
type TaintedFields,
3637
type ValidationErrors,

src/lib/superValidate.ts

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { traversePath } from './traversal.js';
2-
import { type ActionFailure, fail, type RequestEvent } from '@sveltejs/kit';
2+
import { type ActionFailure, fail as kitFail, type RequestEvent } from '@sveltejs/kit';
33
import { type ValidationAdapter, type ValidationResult } from './adapters/adapters.js';
44
import { parseRequest } from './formData.js';
55
import type { ErrorStatus } from './utils.js';
@@ -198,7 +198,7 @@ export function message<
198198
const remove = options?.removeFiles !== false;
199199
const output = remove ? withFiles({ form }) : { form };
200200

201-
return form.valid ? output : fail(options?.status ?? 400, output);
201+
return form.valid ? output : kitFail(options?.status ?? 400, output);
202202
}
203203

204204
export const setMessage = message;
@@ -290,7 +290,7 @@ export function setError<
290290
form.valid = false;
291291

292292
const output = options.removeFiles === false ? { form } : withFiles({ form });
293-
return fail(options.status ?? 400, output);
293+
return kitFail(options.status ?? 400, output);
294294
}
295295

296296
export function withFiles<T extends object>(obj: T) {
@@ -304,3 +304,29 @@ export function withFiles<T extends object>(obj: T) {
304304
}
305305

306306
export const removeFiles = withFiles;
307+
308+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
309+
export function fail<T extends Record<string, unknown> | undefined>(status: number, data?: T) {
310+
function checkForm(
311+
data: unknown
312+
): data is SuperValidated<Record<string, unknown>, unknown, Record<string, unknown>> {
313+
return !!data && typeof data === 'object' && 'valid' in data && 'data' in data && 'id' in data;
314+
}
315+
316+
function checkObj<T extends object>(data: T | undefined) {
317+
if (data && typeof data === 'object') {
318+
for (const key in data) {
319+
const v = data[key];
320+
if (checkForm(v)) {
321+
v.valid = false;
322+
removeFiles(v);
323+
} else if (v && typeof v === 'object') {
324+
checkObj(v);
325+
}
326+
}
327+
}
328+
return data;
329+
}
330+
331+
return kitFail<T>(status, checkObj(data) as T);
332+
}

src/routes/(v2)/v2/Navigation.svelte

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@
5555
'files-proxy',
5656
'tainted-array',
5757
'spa-clearonsubmit',
58-
'app-error'
58+
'app-error',
59+
'form-result-type'
5960
].sort();
6061
</script>
6162

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { zod } from '$lib/adapters/zod.js';
2+
import { superValidate } from '$lib/server/index.js';
3+
import { fail } from '$lib/superValidate.js';
4+
import { schema } from './schema.js';
5+
6+
export const load = async () => {
7+
const form = await superValidate(zod(schema));
8+
return { form };
9+
};
10+
11+
export const actions = {
12+
default: async ({ request }) => {
13+
const formData = await request.formData();
14+
console.log(formData);
15+
16+
const form = await superValidate(formData, zod(schema));
17+
console.log(form);
18+
19+
if (form.data.dir == 'west') {
20+
return { form, code: form.data.dir.toUpperCase() };
21+
}
22+
23+
if (form.data.dir) {
24+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
25+
const f = form as any;
26+
// Testing to add files that should be removed by fail
27+
f.message = new File(['123132123'], 'test.txt');
28+
f.data.extra = new File(['123132123'], 'test2.txt');
29+
return fail(400, { form, code: form.data.dir.toUpperCase() });
30+
} else {
31+
return { form, fail: true };
32+
}
33+
}
34+
};
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<script lang="ts">
2+
import { superForm } from '$lib/client/index.js';
3+
import type { ActionData, PageData } from './$types.js';
4+
5+
export let data: PageData;
6+
7+
const { form, errors, message, enhance } = superForm(data.form, {
8+
taintedMessage: false,
9+
resetForm: true,
10+
onUpdate(event) {
11+
const data = event.result.data as NonNullable<ActionData>;
12+
if (data.fail && event.result.data) {
13+
event.result.data.form.message = 'FAIL';
14+
} else {
15+
event.form.message = data.code;
16+
}
17+
}
18+
});
19+
</script>
20+
21+
{#if $message}<h4 id="message">{$message}</h4>{/if}
22+
23+
<form method="POST" use:enhance>
24+
<div>
25+
<input type="radio" name="dir" value="north" bind:group={$form.dir} /> North<br />
26+
<input type="radio" name="dir" value="south" bind:group={$form.dir} /> South<br />
27+
<input type="radio" name="dir" value="east" bind:group={$form.dir} /> East<br />
28+
<input type="radio" name="dir" value="west" bind:group={$form.dir} /> West (reset)<br />
29+
{#if $errors.dir}<span class="invalid">{$errors.dir}</span>{/if}
30+
</div>
31+
<div>
32+
<button>Submit</button>
33+
</div>
34+
</form>
35+
36+
<style lang="scss">
37+
form {
38+
margin: 2rem 0;
39+
40+
input {
41+
background-color: #dedede;
42+
}
43+
44+
.invalid {
45+
color: crimson;
46+
}
47+
}
48+
</style>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { z } from 'zod';
2+
3+
export const schema = z.object({
4+
dir: z
5+
.enum(['', 'north', 'south', 'east', 'west'])
6+
.refine((dir) => dir != '', 'No direction specified')
7+
});

src/tests/superValidate.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
type SuperValidated
1313
} from '$lib/superValidate.js';
1414
import { merge } from 'ts-deepmerge';
15-
import { fail } from '@sveltejs/kit';
15+
import { fail as kitFail } from '@sveltejs/kit';
1616
import { defaults as schemaDefaults } from '$lib/defaults.js';
1717

1818
///// Adapters //////////////////////////////////////////////////////
@@ -793,7 +793,7 @@ describe('File handling with the allowFiles option', () => {
793793
});
794794

795795
it('should remove the files with the removeFiles function', async () => {
796-
fail(400, withFiles({ form }));
796+
kitFail(400, withFiles({ form }));
797797
expect(form.data.avatar).toBeUndefined();
798798
});
799799
});

0 commit comments

Comments
 (0)