Skip to content

Commit

Permalink
Added tainted to formFieldProxy.
Browse files Browse the repository at this point in the history
  • Loading branch information
ciscoheat committed Oct 2, 2023
1 parent 8bff60b commit 94feac9
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 3 deletions.
8 changes: 6 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@ Headlines: Added, Changed, Deprecated, Removed, Fixed, Security
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
## [1.8.0]

### Fixed

- [Array errors](https://superforms.rocks/concepts/error-handling#form-level-and-array-errors) were always added, even if the form wasn't tainted.
- [Array errors](https://superforms.rocks/concepts/error-handling#form-level-and-array-errors) were always added, even if the array or any data in it hadn't tainted the form.

### Added

- [formFieldProxy](https://superforms.rocks/components#using-a-formfieldproxy) now contains a proxy for `tainted`.

## [1.7.4] - 2023-09-29

Expand Down
39 changes: 38 additions & 1 deletion src/lib/client/proxies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,13 +245,49 @@ export function formFieldProxy<
value: Writable<FormPathType<z.infer<UnwrapEffects<T>>, Path>>;
errors: Writable<string[] | undefined>;
constraints: Writable<InputConstraint | undefined>;
tainted: Writable<boolean | undefined>;
} {
const path2 = splitPath<z.infer<UnwrapEffects<T>>>(path);
// Filter out array indices, the constraints structure doesn't contain these.
const constraintsPath = (path2 as unknown[])
.filter((p) => isNaN(parseInt(String(p))))
.join('.');

const taintedProxy = derived<typeof form.tainted, boolean | undefined>(
form.tainted,
($tainted) => {
if (!$tainted) return $tainted;
const taintedPath = traversePath($tainted, path2);
return taintedPath ? taintedPath.value : undefined;
}
);

const tainted = {
subscribe: taintedProxy.subscribe,
update(upd: Updater<boolean | undefined>) {
form.tainted.update(($tainted) => {
if (!$tainted) $tainted = {};
const output = traversePath($tainted, path2, (path) => {
if (!path.value) path.parent[path.key] = {};
return path.parent[path.key];
});
if (output) output.parent[output.key] = upd(output.value);
return $tainted;
});
},
set(value: boolean | undefined) {
form.tainted.update(($tainted) => {
if (!$tainted) $tainted = {};
const output = traversePath($tainted, path2, (path) => {
if (!path.value) path.parent[path.key] = {};
return path.parent[path.key];
});
if (output) output.parent[output.key] = value;
return $tainted;
});
}
};

return {
path,
value: fieldProxy(form.form, path),
Expand All @@ -261,7 +297,8 @@ export function formFieldProxy<
constraints: fieldProxy(
form.constraints,
constraintsPath as never
) as Writable<InputConstraint | undefined>
) as Writable<InputConstraint | undefined>,
tainted
};
}

Expand Down
1 change: 1 addition & 0 deletions src/routes/Navigation.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
<a href="/tests/flash-onerror">Flash onError</a>
<a href="/tests/reset-component">Reset component 1</a>
<a href="/tests/reset-component-2">Reset component 2</a>
<a href="/tests/tainted-proxy">Tainted formFieldProxy</a>
</nav>

<style lang="scss">
Expand Down
22 changes: 22 additions & 0 deletions src/routes/tests/tainted-proxy/+page.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { message, superValidate } from '$lib/server';
import { schema } from './schema';
import { fail } from '@sveltejs/kit';

export const load = async () => {
const form = await superValidate(schema);
return { form };
};

export const actions = {
default: async ({ request }) => {
const formData = await request.formData();
console.log(formData);

const form = await superValidate(formData, schema);
console.log('POST', form);

if (!form.valid) return fail(400, { form });

return message(form, 'Posted OK!');
}
};
49 changes: 49 additions & 0 deletions src/routes/tests/tainted-proxy/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<script lang="ts">
import { formFieldProxy, superForm } from '$lib/client';
import type { PageData } from './$types';
import SuperDebug from '$lib/client/SuperDebug.svelte';
export let data: PageData;
const form = superForm(data.form, {
dataType: 'json'
});
const { message, tainted: formTainted, enhance } = form;
const { value, errors, tainted } = formFieldProxy(form, 'user.name');
</script>

<SuperDebug data={$formTainted} />

{#if $message}<h4>{$message}</h4>{/if}

<p>Proxy: {$tainted} - Form: {$formTainted?.user?.name}</p>

<p>
<br />
<button on:click={() => ($tainted = false)}>Untaint user.name</button>
</p>

<form method="POST" use:enhance>
<label>
Name: <input name="name" bind:value={$value} />
{#if $errors}<span class="invalid">{$errors}</span>{/if}
</label>
<div>
<button>Submit</button>
</div>
</form>

<style lang="scss">
form {
margin: 2rem 0;
input {
background-color: #dedede;
}
.invalid {
color: crimson;
}
}
</style>
7 changes: 7 additions & 0 deletions src/routes/tests/tainted-proxy/schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { z } from 'zod';

export const schema = z.object({
user: z.object({
name: z.string().min(1)
})
});

0 comments on commit 94feac9

Please # to comment.