Skip to content

Commit e52fa88

Browse files
committed
Superstruct fixes
1 parent 970da6a commit e52fa88

File tree

6 files changed

+96
-13
lines changed

6 files changed

+96
-13
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313

1414
### Fixed
1515

16-
- Type inference for validation errors didn't include `_errors` for objects, only for arrays.
16+
- Type inference for validation errors didn't include `_errors` for all objects, only for arrays.
1717

1818
## [2.15.2] - 2024-06-26
1919

src/lib/adapters/superstruct.ts

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,10 @@ import {
1010
import type { Struct } from 'superstruct';
1111
import { memoize } from '$lib/memoize.js';
1212

13-
// async function modules() {
14-
// const { validate } = await import(/* webpackIgnore: true */ 'superstruct');
15-
// return { validate };
16-
// }
17-
18-
// const fetchModule = /* @__PURE__ */ memoize(modules);
19-
2013
// eslint-disable-next-line @typescript-eslint/no-explicit-any
21-
async function validate<T extends Struct<any, any>>(
14+
type StructObject<T extends Record<string, unknown>> = Struct<T, any>;
15+
16+
async function validate<T extends StructObject<Infer<T>>>(
2217
schema: T,
2318
data: unknown
2419
): Promise<ValidationResult<Infer<T>>> {
@@ -39,8 +34,7 @@ async function validate<T extends Struct<any, any>>(
3934
};
4035
}
4136

42-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
43-
function _superstruct<T extends Struct<any, any>>(
37+
function _superstruct<T extends StructObject<Infer<T>>>(
4438
schema: T,
4539
options: RequiredDefaultsOptions<Infer<T>>
4640
): ValidationAdapter<Infer<T>> {
@@ -52,7 +46,9 @@ function _superstruct<T extends Struct<any, any>>(
5246
});
5347
}
5448

55-
function _superstructClient<T extends Struct>(schema: T): ClientValidationAdapter<Infer<T>> {
49+
function _superstructClient<T extends StructObject<Infer<T>>>(
50+
schema: T
51+
): ClientValidationAdapter<Infer<T>> {
5652
return {
5753
superFormValidationLibrary: 'superstruct',
5854
validate: async (data) => validate(schema, data)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { superstruct } from '$lib/adapters/superstruct.js';
2+
import { message, superValidate } from '$lib/server/index.js';
3+
import { schema } from './schema.js';
4+
import { fail } from '@sveltejs/kit';
5+
6+
const defaults = { name: '', email: '' };
7+
8+
export const load = async () => {
9+
const form = await superValidate(superstruct(schema, { defaults }));
10+
return { form };
11+
};
12+
13+
export const actions = {
14+
default: async ({ request }) => {
15+
const formData = await request.formData();
16+
console.log(formData);
17+
18+
const form = await superValidate(formData, superstruct(schema, { defaults }));
19+
console.log(form);
20+
21+
if (!form.valid) return fail(400, { form });
22+
23+
return message(form, 'Posted OK!');
24+
}
25+
};
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<script lang="ts">
2+
import { superForm } from '$lib/client/index.js';
3+
import SuperDebug from '$lib/client/SuperDebug.svelte';
4+
import { superstructClient } from '$lib/adapters/superstruct.js';
5+
import { schema } from './schema.js';
6+
7+
export let data;
8+
9+
const { form, errors, tainted, message, enhance } = superForm(data.form, {
10+
taintedMessage: false,
11+
//dataType: 'json',
12+
validators: superstructClient(schema)
13+
});
14+
</script>
15+
16+
<SuperDebug data={{ $form, $errors, $tainted }} />
17+
18+
{#if $message}<h4>{$message}</h4>{/if}
19+
20+
<form method="POST" use:enhance>
21+
<label>
22+
Name: <input
23+
name="name"
24+
bind:value={$form.name}
25+
aria-invalid={$errors.name ? 'true' : undefined}
26+
/>
27+
{#if $errors.name}<span class="invalid">{$errors.name}</span>{/if}
28+
</label>
29+
<label>
30+
Email: <input
31+
name="email"
32+
bind:value={$form.email}
33+
aria-invalid={$errors.email ? 'true' : undefined}
34+
/>
35+
{#if $errors.email}<span class="invalid">{$errors.email}</span>{/if}
36+
</label>
37+
<div>
38+
<button>Submit</button>
39+
</div>
40+
</form>
41+
42+
<style lang="scss">
43+
form {
44+
margin: 2rem 0;
45+
46+
input {
47+
background-color: #dedede;
48+
}
49+
50+
.invalid {
51+
color: crimson;
52+
}
53+
}
54+
</style>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { object, string, size, define } from 'superstruct';
2+
3+
const email = () => define<string>('email', (value) => String(value).includes('@'));
4+
5+
export const schema = object({
6+
name: size(string(), 2, 100),
7+
email: email()
8+
});

src/tests/superValidate.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -761,7 +761,7 @@ describe('vine', () => {
761761
});
762762

763763
describe('superstruct', () => {
764-
const email = () => ssDefine('email', (value) => String(value).includes('@'));
764+
const email = () => ssDefine<string>('email', (value) => String(value).includes('@'));
765765

766766
const schema = ssObject({
767767
name: ssOptional(ssString()),

0 commit comments

Comments
 (0)