Skip to content

Commit

Permalink
Validate search params
Browse files Browse the repository at this point in the history
  • Loading branch information
jnicklas committed Nov 5, 2024
1 parent 259766c commit d4b31a8
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 62 deletions.
5 changes: 5 additions & 0 deletions .changeset/flat-ads-ring.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"signal-form": patch
---

Validate search params
64 changes: 33 additions & 31 deletions lib/utils/parse-form-data.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,42 @@
type ParsedObject = { [key: string]: any };
export function parseFormData(data: any): any {
if (data instanceof URLSearchParams || data instanceof FormData) {
let result: any = {};

export function parseFormData(formData: FormData): ParsedObject {
let result: ParsedObject = {};
// Iterate over each form data entry
for (let [key, value] of data) {
let current = result;
let keys = key.split(/[\.\[\]]/).filter((k) => k !== ""); // Split the key into parts and filter out empty strings

// Iterate over each form data entry
for (let [key, value] of formData) {
let current = result;
let keys = key.split(/[\.\[\]]/).filter((k) => k !== ""); // Split the key into parts and filter out empty strings

keys.forEach((k, index) => {
// Check if it's the last key
if (index === keys.length - 1) {
// Keys may occur multiple times in the form data, this could be the
// case for multi-selects for example. In this case we need to convert
// the value to an array.
if (current.hasOwnProperty(k)) {
// if it's already an array, append the value, otherwise convert it
if (Array.isArray(current[k])) {
current[k] = [...current[k], value];
keys.forEach((k, index) => {
// Check if it's the last key
if (index === keys.length - 1) {
// Keys may occur multiple times in the form data, this could be the
// case for multi-selects for example. In this case we need to convert
// the value to an array.
if (current.hasOwnProperty(k)) {
// if it's already an array, append the value, otherwise convert it
if (Array.isArray(current[k])) {
current[k] = [...current[k], value];
} else {
current[k] = [current[k], value];
}
} else {
current[k] = [current[k], value];
current[k] = value;
}
} else {
current[k] = value;
}
} else {
// Initialize the next level in the structure if it doesn't exist
if (!current[k]) {
current[k] = isNaN(parseInt(keys[index + 1] || "")) ? {} : [];
// Initialize the next level in the structure if it doesn't exist
if (!current[k]) {
current[k] = isNaN(parseInt(keys[index + 1] || "")) ? {} : [];
}

// Move to the next level in the structure
current = current[k];
}
});
}

// Move to the next level in the structure
current = current[k];
}
});
return result;
} else {
return data;
}

return result;
}
36 changes: 5 additions & 31 deletions lib/utils/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@ export function validateSync<T extends AnyObjectSchema>(
input: any
): ValidationResult<InferType<T>> {
try {
let parsedInput = input instanceof FormData ? parseFormData(input) : input;
let validationResult = schema.validateSync(parsedInput, {
let validationResult = schema.validateSync(parseFormData(input), {
abortEarly: false,
});
return { ok: true, input, status: "valid", data: validationResult };
Expand All @@ -57,8 +56,7 @@ export async function validate<T extends AnyObjectSchema>(
input: any
): Promise<ValidationResult<InferType<T>>> {
try {
let parsedInput = input instanceof FormData ? parseFormData(input) : input;
let validationResult = await schema.validate(parsedInput, {
let validationResult = await schema.validate(parseFormData, {
abortEarly: false,
});
return { ok: true, input, status: "valid", data: validationResult };
Expand All @@ -84,42 +82,18 @@ export async function validateOrThrow<T extends AnyObjectSchema>(
}
}

export async function validateFormData<T extends AnyObjectSchema>(
schema: T,
formData: FormData
): Promise<ValidationResult<InferType<T>>> {
let object = parseFormData(formData);
return await validate(schema, object);
}

export async function validateFormDataOrThrow<T extends AnyObjectSchema>(
schema: T,
formData: FormData
): Promise<InferType<T>> {
let result = await validateFormData(schema, formData);
if (result.ok) {
return result.data;
} else {
throw new ValidationErrorException(formData, result.errors);
}
}

export async function validateRequest<T extends AnyObjectSchema>(
schema: T,
request: Request
): Promise<ValidationResult<InferType<T>>> {
let formData = await request.formData();
return await validateFormData(schema, formData);
return await validate(schema, formData);
}

export async function validateRequestOrThrow<T extends AnyObjectSchema>(
schema: T,
request: Request
): Promise<InferType<T>> {
let result = await validateRequest(schema, request);
if (result.ok) {
return result.data;
} else {
throw new ValidationErrorException(request, result.errors);
}
let formData = await request.formData();
return await validateOrThrow(schema, formData);
}

0 comments on commit d4b31a8

Please sign in to comment.