sveltekit-superforms
Advanced tools
Comparing version 2.9.0 to 2.10.0
@@ -8,7 +8,7 @@ import { createAdapter } from './adapters.js'; | ||
dateStrategy: 'integer', | ||
ignoreUnknownValidation: true | ||
ignoreUnknownValidation: true, | ||
customSchemaConversion: { special: () => ({}), instance: () => ({}) } | ||
}; | ||
/* @__NO_SIDE_EFFECTS__ */ | ||
export const valibotToJSONSchema = (options) => { | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
return valibotToJSON({ ...defaultOptions, ...options }); | ||
@@ -15,0 +15,0 @@ }; |
export { superForm } from './superForm.js'; | ||
export { intProxy, numberProxy, booleanProxy, dateProxy, fieldProxy, formFieldProxy, stringProxy, arrayProxy, type FieldProxy, type ArrayProxy, type FormFieldProxy } from './proxies.js'; | ||
export { intProxy, numberProxy, booleanProxy, dateProxy, fieldProxy, formFieldProxy, stringProxy, arrayProxy, fileProxy, fileFieldProxy, filesProxy, filesFieldProxy, type FieldProxy, type ArrayProxy, type FormFieldProxy } from './proxies.js'; | ||
export { defaults, defaultValues } from '../defaults.js'; | ||
@@ -4,0 +4,0 @@ export { actionResult } from '../actionResult.js'; |
// Backwards compatibility, everything should be imported from top-level in v2. | ||
export { superForm } from './superForm.js'; | ||
export { intProxy, numberProxy, booleanProxy, dateProxy, fieldProxy, formFieldProxy, stringProxy, arrayProxy } from './proxies.js'; | ||
export { intProxy, numberProxy, booleanProxy, dateProxy, fieldProxy, formFieldProxy, stringProxy, arrayProxy, fileProxy, fileFieldProxy, filesProxy, filesFieldProxy } from './proxies.js'; | ||
///////////////////////////////////////////////////////////////////// | ||
@@ -5,0 +5,0 @@ // Duplicated from server/index.ts, |
@@ -14,2 +14,3 @@ /// <reference types="svelte" /> | ||
type PathType<Type, T, Path extends string> = IsAny<Type> extends true ? FormPathType<T, Path> : Type; | ||
type Nullable<T extends Record<string, unknown>, Path extends FormPaths<T> | FormPathArrays<T> | FormPathLeaves<T>> = null extends FormPathType<T, Path> ? null : never; | ||
type DefaultOptions = { | ||
@@ -23,6 +24,6 @@ trueStringValue: string; | ||
}; | ||
export declare function booleanProxy<T extends Record<string, unknown>, Path extends FormPaths<T>>(form: Writable<T> | SuperForm<T, unknown>, path: Path, options?: Prettify<Pick<DefaultOptions, 'trueStringValue' | 'taint'>>): CorrectProxyType<boolean, string, T, Path>; | ||
export declare function intProxy<T extends Record<string, unknown>, Path extends FormPaths<T>>(form: Writable<T> | SuperForm<T, unknown>, path: Path, options?: Prettify<Pick<DefaultOptions, 'empty' | 'initiallyEmptyIfZero' | 'taint'>>): CorrectProxyType<number, string, T, Path>; | ||
export declare function numberProxy<T extends Record<string, unknown>, Path extends FormPaths<T>>(form: Writable<T> | SuperForm<T, unknown>, path: Path, options?: Prettify<Pick<DefaultOptions, 'empty' | 'delimiter' | 'initiallyEmptyIfZero' | 'taint'>>): CorrectProxyType<number, string, T, Path>; | ||
export declare function dateProxy<T extends Record<string, unknown>, Path extends FormPaths<T>>(form: Writable<T> | SuperForm<T, unknown>, path: Path, options?: { | ||
export declare function booleanProxy<T extends Record<string, unknown>, Path extends FormPaths<T>>(form: Writable<T> | SuperForm<T>, path: Path, options?: Prettify<Pick<DefaultOptions, 'trueStringValue' | 'taint'>>): CorrectProxyType<boolean, string, T, Path>; | ||
export declare function intProxy<T extends Record<string, unknown>, Path extends FormPaths<T>>(form: Writable<T> | SuperForm<T>, path: Path, options?: Prettify<Pick<DefaultOptions, 'empty' | 'initiallyEmptyIfZero' | 'taint'>>): CorrectProxyType<number, string, T, Path>; | ||
export declare function numberProxy<T extends Record<string, unknown>, Path extends FormPaths<T>>(form: Writable<T> | SuperForm<T>, path: Path, options?: Prettify<Pick<DefaultOptions, 'empty' | 'delimiter' | 'initiallyEmptyIfZero' | 'taint'>>): CorrectProxyType<number, string, T, Path>; | ||
export declare function dateProxy<T extends Record<string, unknown>, Path extends FormPaths<T>>(form: Writable<T> | SuperForm<T>, path: Path, options?: { | ||
format?: DefaultOptions['dateFormat']; | ||
@@ -32,14 +33,35 @@ empty?: Exclude<DefaultOptions['empty'], 'zero'>; | ||
}): CorrectProxyType<Date, string, T, Path>; | ||
export declare function stringProxy<T extends Record<string, unknown>, Path extends FormPaths<T>>(form: Writable<T> | SuperForm<T, unknown>, path: Path, options: { | ||
export declare function stringProxy<T extends Record<string, unknown>, Path extends FormPaths<T>>(form: Writable<T> | SuperForm<T>, path: Path, options: { | ||
empty: NonNullable<Exclude<DefaultOptions['empty'], 'zero'>>; | ||
taint?: TaintOption; | ||
}): Writable<string>; | ||
export declare function fileFieldProxy<T extends Record<string, unknown>, Path extends FormPathLeaves<T, File>>(form: SuperForm<T>, path: Path, options?: ProxyOptions): FormFieldProxy<FileList | File | Nullable<T, Path>, Path>; | ||
export declare function fileProxy<T extends Record<string, unknown>, Path extends FormPathLeaves<T, File>>(form: Writable<T> | SuperForm<T>, path: Path, options?: ProxyOptions): { | ||
subscribe(this: void, run: (value: FileList) => void): import("svelte/store").Unsubscriber; | ||
set(this: void, file: FileList | File | Nullable<T, Path>): void; | ||
update(this: void): never; | ||
}; | ||
export declare function filesFieldProxy<T extends Record<string, unknown>, Path extends FormPathArrays<T, File[]>>(form: SuperForm<T>, path: Path, options?: ProxyOptions): { | ||
values: { | ||
subscribe(this: void, run: (value: FileList) => void): import("svelte/store").Unsubscriber; | ||
set(this: void, files: FileList | File[] | Nullable<T, Path>): void; | ||
update(this: void): never; | ||
}; | ||
path: Path; | ||
errors: Writable<string[] | undefined>; | ||
valueErrors: Writable<ValueErrors>; | ||
}; | ||
export declare function filesProxy<T extends Record<string, unknown>, Path extends FormPathArrays<T, File[]>>(form: Writable<T> | SuperForm<T>, path: Path, options?: ProxyOptions): { | ||
subscribe(this: void, run: (value: FileList) => void): import("svelte/store").Unsubscriber; | ||
set(this: void, files: FileList | File[] | Nullable<T, Path>): void; | ||
update(this: void): never; | ||
}; | ||
type ValueErrors = any[]; | ||
export type ArrayProxy<T, Path = string, Errors = ValueErrors> = { | ||
export type ArrayProxy<T, Path = string, Errors = ValueErrors, ExtraValues = never> = { | ||
path: Path; | ||
values: Writable<T[] & unknown[]>; | ||
values: Writable<(T[] & unknown[]) | ExtraValues>; | ||
errors: Writable<string[] | undefined>; | ||
valueErrors: Writable<Errors>; | ||
}; | ||
export declare function arrayProxy<T extends Record<string, unknown>, Path extends FormPathArrays<T, ArrType>, ArrType = any>(superForm: SuperForm<T, any>, path: Path, options?: { | ||
export declare function arrayProxy<T extends Record<string, unknown>, Path extends FormPathArrays<T, ArrType>, ArrType = any>(superForm: SuperForm<T>, path: Path, options?: { | ||
taint?: TaintOption; | ||
@@ -54,3 +76,3 @@ }): ArrayProxy<FormPathType<T, Path> extends (infer U)[] ? U : never, Path>; | ||
}; | ||
export declare function formFieldProxy<T extends Record<string, unknown>, Path extends FormPathLeaves<T, Type>, Type = any>(superForm: SuperForm<T, any>, path: Path, options?: ProxyOptions): FormFieldProxy<PathType<Type, T, Path>, Path>; | ||
export declare function formFieldProxy<T extends Record<string, unknown>, Path extends FormPathLeaves<T, Type>, Type = any>(superForm: SuperForm<T>, path: Path, options?: ProxyOptions): FormFieldProxy<PathType<Type, T, Path>, Path>; | ||
type SuperFieldProxy<T> = { | ||
@@ -66,3 +88,3 @@ subscribe: Readable<T>['subscribe']; | ||
export type FieldProxy<T> = Writable<T>; | ||
export declare function fieldProxy<T extends Record<string, unknown>, Path extends FormPaths<T, Type>, Type = any>(form: Writable<T> | SuperForm<T, unknown>, path: Path, options?: ProxyOptions): FieldProxy<PathType<Type, T, Path>>; | ||
export declare function fieldProxy<T extends Record<string, unknown>, Path extends FormPaths<T, Type>, Type = any>(form: Writable<T> | SuperForm<T>, path: Path, options?: ProxyOptions): FieldProxy<PathType<Type, T, Path>>; | ||
export {}; |
/* eslint-disable @typescript-eslint/no-explicit-any */ | ||
import { derived, get } from 'svelte/store'; | ||
import { derived, get, writable } from 'svelte/store'; | ||
import { SuperFormError } from '../errors.js'; | ||
import { pathExists, traversePath } from '../traversal.js'; | ||
import { splitPath } from '../stringPath.js'; | ||
import { browser } from '$app/environment'; | ||
const defaultOptions = { | ||
@@ -42,2 +43,90 @@ trueStringValue: 'true', | ||
} | ||
export function fileFieldProxy(form, path, options) { | ||
const fileField = fileProxy(form, path, options); | ||
const formField = formFieldProxy(form, path, options); | ||
return { ...formField, value: fileField }; | ||
} | ||
export function fileProxy(form, path, options) { | ||
const formFile = fieldProxy(form, path, options); | ||
const fileProxy = writable(browser ? new DataTransfer().files : {}); | ||
formFile.subscribe((file) => { | ||
if (!browser) | ||
return; | ||
const dt = new DataTransfer(); | ||
if (file) | ||
dt.items.add(file); | ||
fileProxy.set(dt.files); | ||
}); | ||
const fileStore = { | ||
subscribe(run) { | ||
return fileProxy.subscribe(run); | ||
}, | ||
set(file) { | ||
if (!browser) | ||
return; | ||
if (!file || file instanceof File) { | ||
const dt = new DataTransfer(); | ||
if (file) | ||
dt.items.add(file); | ||
else | ||
formFile.set(file); | ||
file = dt.files; | ||
} | ||
fileProxy.set(file); | ||
if (file.length > 0) | ||
formFile.set(file.item(0)); | ||
}, | ||
update() { | ||
throw new SuperFormError('You cannot update a fileProxy, only set it.'); | ||
} | ||
}; | ||
return fileStore; | ||
} | ||
export function filesFieldProxy(form, path, options) { | ||
const filesStore = filesProxy(form, path, options); | ||
const arrayField = arrayProxy(form, path, options); | ||
return { ...arrayField, values: filesStore }; | ||
} | ||
export function filesProxy(form, path, options) { | ||
const formFiles = fieldProxy(form, path, options); | ||
const filesProxy = writable(browser ? new DataTransfer().files : {}); | ||
formFiles.subscribe((files) => { | ||
if (!browser) | ||
return; | ||
const dt = new DataTransfer(); | ||
if (files) | ||
files.forEach((file) => dt.items.add(file)); | ||
filesProxy.set(dt.files); | ||
}); | ||
const filesStore = { | ||
subscribe(run) { | ||
return filesProxy.subscribe(run); | ||
}, | ||
set(files) { | ||
if (!browser) | ||
return; | ||
if (!(files instanceof FileList)) { | ||
const dt = new DataTransfer(); | ||
if (Array.isArray(files)) | ||
files.forEach((file) => dt.items.add(file)); | ||
else | ||
formFiles.set(files); | ||
files = dt.files; | ||
} | ||
const newFiles = files; | ||
filesProxy.set(newFiles); | ||
const output = []; | ||
for (let i = 0; i < newFiles.length; i++) { | ||
const file = newFiles.item(i); | ||
if (file) | ||
output.push(file); | ||
} | ||
formFiles.set(output); | ||
}, | ||
update() { | ||
throw new SuperFormError('You cannot update a fileProxy, only set it.'); | ||
} | ||
}; | ||
return filesStore; | ||
} | ||
///// Implementation //////////////////////////////////////////////// | ||
@@ -44,0 +133,0 @@ /** |
@@ -686,2 +686,3 @@ import { derived, get, readonly, writable } from 'svelte/store'; | ||
const paths = comparePaths(newData, Data.form); | ||
const newTainted = comparePaths(newData, Tainted.clean).map((path) => path.join()); | ||
if (paths.length) { | ||
@@ -692,7 +693,9 @@ if (taintOptions == 'untaint-all' || taintOptions == 'untaint-form') { | ||
else { | ||
Tainted.state.update((tainted) => { | ||
if (!tainted) | ||
tainted = {}; | ||
setPaths(tainted, paths, (path, data) => { | ||
Tainted.state.update((currentlyTainted) => { | ||
if (!currentlyTainted) | ||
currentlyTainted = {}; | ||
setPaths(currentlyTainted, paths, (path, data) => { | ||
// If value goes back to the clean value, untaint the path | ||
if (!newTainted.includes(path.join())) | ||
return undefined; | ||
const currentValue = traversePath(newData, path); | ||
@@ -708,3 +711,3 @@ const cleanPath = traversePath(Tainted.clean, path); | ||
}); | ||
return tainted; | ||
return currentlyTainted; | ||
}); | ||
@@ -840,18 +843,17 @@ } | ||
const { taintedMessage } = options; | ||
const isTaintedFunction = typeof taintedMessage === 'function'; | ||
// As beforeNavigate does not support Promise, we cancel the redirection until the promise resolve | ||
nav.cancel(); | ||
// Does not display any dialog on page refresh or closing tab and let the default browser behaviour | ||
// if it's a custom function | ||
if (isTaintedFunction) | ||
nav.cancel(); | ||
// Does not display any dialog on page refresh or closing tab, will use default browser behaviour | ||
if (nav.type === 'leave') | ||
return; | ||
const isTaintedFunction = typeof taintedMessage === 'function'; | ||
const message = isTaintedFunction || taintedMessage === true ? defaultMessage : taintedMessage; | ||
// - rejected => shouldRedirect = false | ||
// - resolved with false => shouldRedirect = false | ||
// - resolved with true => shouldRedirect = true | ||
const confirmFunction = isTaintedFunction | ||
? taintedMessage | ||
: () => window.confirm(message); | ||
let shouldRedirect; | ||
try { | ||
shouldRedirect = await confirmFunction(); | ||
// - rejected => shouldRedirect = false | ||
// - resolved with false => shouldRedirect = false | ||
// - resolved with true => shouldRedirect = true | ||
shouldRedirect = isTaintedFunction ? await taintedMessage() : window.confirm(message); | ||
} | ||
@@ -872,2 +874,5 @@ catch { | ||
} | ||
else if (!shouldRedirect && !isTaintedFunction) { | ||
nav.cancel(); | ||
} | ||
} | ||
@@ -874,0 +879,0 @@ } |
@@ -6,4 +6,4 @@ import SuperDebug from './client/SuperDebug.svelte'; | ||
export type { JSONSchema } from './jsonSchema/index.js'; | ||
export { superForm, intProxy, numberProxy, booleanProxy, dateProxy, fieldProxy, formFieldProxy, stringProxy, arrayProxy, defaults, defaultValues, schemaShape, actionResult, superValidate, message, setMessage, setError, withFiles, removeFiles, type SuperValidated, type TaintedFields, type ValidationErrors, type Infer, type InferIn, type Schema, type FormResult, type FormOptions, type SuperForm, type SuperFormEventList, type SuperFormEvents, type SuperFormSnapshot, type ValidateOptions, type TaintOption, type FormPath, type FormPathLeaves, type FormPathArrays, type FormPathType, type ChangeEvent, type FieldProxy, type ArrayProxy, type FormFieldProxy } from './client/index.js'; | ||
export { superForm, intProxy, numberProxy, booleanProxy, dateProxy, fieldProxy, formFieldProxy, stringProxy, arrayProxy, fileProxy, fileFieldProxy, filesProxy, filesFieldProxy, defaults, defaultValues, schemaShape, actionResult, superValidate, message, setMessage, setError, withFiles, removeFiles, type SuperValidated, type TaintedFields, type ValidationErrors, type Infer, type InferIn, type Schema, type FormResult, type FormOptions, type SuperForm, type SuperFormEventList, type SuperFormEvents, type SuperFormSnapshot, type ValidateOptions, type TaintOption, type FormPath, type FormPathLeaves, type FormPathArrays, type FormPathType, type ChangeEvent, type FieldProxy, type ArrayProxy, type FormFieldProxy } from './client/index.js'; | ||
export { splitPath } from './stringPath.js'; | ||
export type { ErrorStatus } from './utils.js'; |
@@ -5,3 +5,3 @@ import SuperDebug from './client/SuperDebug.svelte'; | ||
// Everything from client/index.ts | ||
export { superForm, intProxy, numberProxy, booleanProxy, dateProxy, fieldProxy, formFieldProxy, stringProxy, arrayProxy, defaults, defaultValues, schemaShape, actionResult, superValidate, message, setMessage, setError, withFiles, removeFiles } from './client/index.js'; | ||
export { superForm, intProxy, numberProxy, booleanProxy, dateProxy, fieldProxy, formFieldProxy, stringProxy, arrayProxy, fileProxy, fileFieldProxy, filesProxy, filesFieldProxy, defaults, defaultValues, schemaShape, actionResult, superValidate, message, setMessage, setError, withFiles, removeFiles } from './client/index.js'; | ||
export { splitPath } from './stringPath.js'; |
@@ -27,3 +27,3 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ | ||
let parent = obj; | ||
while (path.length < realPath.length) { | ||
while (parent && path.length < realPath.length) { | ||
const key = path[path.length - 1]; | ||
@@ -91,4 +91,16 @@ const value = modifier | ||
const diffPaths = new Map(); | ||
function builtInDiff(one, other) { | ||
if (one instanceof Date && other instanceof Date && one.getTime() !== other.getTime()) | ||
return true; | ||
if (one instanceof Set && other instanceof Set && !eqSet(one, other)) | ||
return true; | ||
if (one instanceof File && other instanceof File && one !== other) | ||
return true; | ||
return false; | ||
} | ||
function isBuiltin(data) { | ||
return data instanceof Date || data instanceof Set || data instanceof File; | ||
} | ||
function checkPath(data, compareTo) { | ||
const exists = compareTo ? traversePath(compareTo, data.path) : undefined; | ||
const otherData = compareTo ? traversePath(compareTo, data.path) : undefined; | ||
function addDiff() { | ||
@@ -98,24 +110,12 @@ diffPaths.set(data.path.join(' '), data.path); | ||
} | ||
if (isBuiltin(data.value)) { | ||
if (!isBuiltin(otherData?.value) || builtInDiff(data.value, otherData.value)) { | ||
return addDiff(); | ||
} | ||
} | ||
if (data.isLeaf) { | ||
if (!exists) { | ||
if (!otherData || data.value !== otherData.value) { | ||
addDiff(); | ||
} | ||
else if (data.value !== exists.value) { | ||
addDiff(); | ||
} | ||
} | ||
else if (exists) { | ||
if ((data.value instanceof Date || exists.value instanceof Date) && | ||
(!!data.value != !!exists.value || data.value.getTime() != exists.value.getTime())) { | ||
return addDiff(); | ||
} | ||
else if ((data.value instanceof Set || exists.value instanceof Set) && | ||
(!!data.value != !!exists.value || !eqSet(data.value, exists.value))) { | ||
return addDiff(); | ||
} | ||
else if ((data.value instanceof File || exists.value instanceof File) && | ||
(!!data.value != !!exists.value || data.value !== exists.value)) { | ||
return addDiff(); | ||
} | ||
} | ||
} | ||
@@ -122,0 +122,0 @@ traversePaths(newObj, (data) => checkPath(data, oldObj)); |
{ | ||
"name": "sveltekit-superforms", | ||
"version": "2.9.0", | ||
"version": "2.10.0", | ||
"author": "Andreas Söderlund <ciscoheat@gmail.com> (https://blog.encodeart.dev)", | ||
@@ -119,10 +119,10 @@ "description": "Making SvelteKit forms a pleasure to use!", | ||
"optionalDependencies": { | ||
"@gcornut/valibot-json-schema": "^0.0.25", | ||
"@gcornut/valibot-json-schema": "^0.0.26", | ||
"@sinclair/typebox": "^0.32.15", | ||
"@sodaru/yup-to-json-schema": "^2.0.1", | ||
"@vinejs/vine": "^1.7.1", | ||
"@vinejs/vine": "^1.8.0", | ||
"arktype": "1.0.29-alpha", | ||
"joi": "^17.12.2", | ||
"superstruct": "^1.0.3", | ||
"valibot": "^0.29.0", | ||
"superstruct": "^1.0.4", | ||
"valibot": "^0.30.0", | ||
"yup": "^1.4.0", | ||
@@ -140,7 +140,7 @@ "zod": "^3.22.4", | ||
"@sveltejs/adapter-auto": "^3.1.1", | ||
"@sveltejs/kit": "^2.5.2", | ||
"@sveltejs/package": "^2.2.7", | ||
"@sveltejs/kit": "^2.5.4", | ||
"@sveltejs/package": "^2.3.0", | ||
"@sveltejs/vite-plugin-svelte": "^3.0.2", | ||
"@types/json-schema": "^7.0.15", | ||
"@types/node": "^20.11.25", | ||
"@types/node": "^20.11.28", | ||
"@types/throttle-debounce": "^5.0.2", | ||
@@ -153,4 +153,4 @@ "@types/uuid": "^9.0.8", | ||
"eslint-plugin-dci-lint": "^0.3.2", | ||
"eslint-plugin-svelte": "2.36.0-next.8", | ||
"json-schema-to-ts": "^3.0.0", | ||
"eslint-plugin-svelte": "2.36.0-next.10", | ||
"json-schema-to-ts": "^3.0.1", | ||
"only-allow": "^1.2.1", | ||
@@ -160,8 +160,8 @@ "prettier": "^3.2.5", | ||
"publint": "^0.2.7", | ||
"sass": "^1.71.1", | ||
"svelte": "5.0.0-next.70", | ||
"svelte-check": "^3.6.6", | ||
"sass": "^1.72.0", | ||
"svelte": "5.0.0-next.80", | ||
"svelte-check": "^3.6.7", | ||
"svelte-french-toast": "^1.2.0", | ||
"sveltekit-flash-message": "^2.4.4", | ||
"sveltekit-rate-limiter": "^0.4.3", | ||
"sveltekit-rate-limiter": "^0.5.1", | ||
"throttle-debounce": "^5.0.0", | ||
@@ -171,4 +171,4 @@ "tslib": "^2.6.2", | ||
"uuid": "^9.0.1", | ||
"vite": "^5.1.5", | ||
"vitest": "^1.3.1" | ||
"vite": "^5.1.6", | ||
"vitest": "^1.4.0" | ||
}, | ||
@@ -175,0 +175,0 @@ "svelte": "./dist/index.js", |
265749
5625
110