Skip to content

Commit

Permalink
feat(conform-react): make error array only
Browse files Browse the repository at this point in the history
  • Loading branch information
edmundhung committed Jul 18, 2023
1 parent 217af69 commit 30a972b
Show file tree
Hide file tree
Showing 20 changed files with 165 additions and 203 deletions.
12 changes: 6 additions & 6 deletions examples/remix/app/routes/login-fetcher.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,22 @@ interface SignupForm {
function parseFormData(formData: FormData) {
return parse<SignupForm>(formData, {
resolve({ email, password, confirmPassword }) {
const error: Record<string, string> = {};
const error: Record<string, string[]> = {};

if (!email) {
error.email = 'Email is required';
error.email = ['Email is required'];
} else if (!email.includes('@')) {
error.email = 'Email is invalid';
error.email = ['Email is invalid'];
}

if (!password) {
error.password = 'Password is required';
error.password = ['Password is required'];
}

if (!confirmPassword) {
error.confirmPassword = 'Confirm password is required';
error.confirmPassword = ['Confirm password is required'];
} else if (confirmPassword !== password) {
error.confirmPassword = 'Password does not match';
error.confirmPassword = ['Password does not match'];
}

if (error.email || error.password || error.confirmPassword) {
Expand Down
56 changes: 26 additions & 30 deletions packages/conform-dom/formdata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,25 +26,24 @@ export function getFormData(
* ```
*/
export function getPaths(name: string): Array<string | number> {
const pattern = /(\w*)\[(\d+)\]/;

if (!name) {
return [];
}

return name.split('.').flatMap((key) => {
const matches = pattern.exec(key);

if (!matches) {
return key;
}

if (matches[1] === '') {
return Number(matches[2]);
}

return [matches[1], Number(matches[2])];
});
return name
.split(/\.|(\[\d*\])/)
.reduce<Array<string | number>>((result, segment) => {
if (typeof segment !== 'undefined' && segment !== '') {
if (segment.startsWith('[') && segment.endsWith(']')) {
const index = segment.slice(1, -1);

result.push(Number(index));
} else {
result.push(segment);
}
}
return result;
}, []);
}

/**
Expand Down Expand Up @@ -72,22 +71,23 @@ export function formatPaths(paths: Array<string | number>): string {
* Assign a value to a target object by following the paths on the name
*/
export function setValue(
target: any,
target: Record<string, any>,
name: string,
valueFn: (prev?: unknown) => any,
): void {
let paths = getPaths(name);
let length = paths.length;
let lastIndex = length - 1;
const paths = getPaths(name);
const length = paths.length;
const lastIndex = length - 1;

let index = -1;
let pointer = target;

while (pointer != null && ++index < length) {
let key = paths[index];
let next = paths[index + 1];
let newValue =
const key = paths[index] as string | number;
const nextKey = paths[index + 1];
const newValue =
index != lastIndex
? pointer[key] ?? (typeof next === 'number' ? [] : {})
? pointer[key] ?? (typeof nextKey === 'number' ? [] : {})
: valueFn(pointer[key]);

pointer[key] = newValue;
Expand Down Expand Up @@ -144,17 +144,13 @@ export function resolve(
/**
* Format the error messages into a validation message
*/
export function getValidationMessage(errors?: string | string[]): string {
return ([] as string[]).concat(errors ?? []).join(String.fromCharCode(31));
export function getValidationMessage(errors?: string[]): string {
return errors?.join(String.fromCharCode(31)) ?? '';
}

/**
* Retrieve the error messages from the validation message
*/
export function getErrors(validationMessage: string | undefined): string[] {
if (!validationMessage) {
return [];
}

return validationMessage.split(String.fromCharCode(31));
return validationMessage?.split(String.fromCharCode(31)) ?? [];
}
16 changes: 8 additions & 8 deletions packages/conform-dom/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { INTENT, getIntent, parseIntent, updateList } from './intent.js';
export type Submission<Schema = any> = {
intent: string;
payload: Record<string, any>;
error: Record<string, string | string[]>;
error: Record<string, string[]>;
value?: Schema | null;
};

Expand All @@ -18,7 +18,7 @@ export function parse<Schema>(
resolve?: (
payload: Record<string, any>,
intent: string,
) => { value?: Schema; error?: Record<string, string | string[]> };
) => { value?: Schema; error?: Record<string, string[]> };
stripEmptyValue?: boolean;
},
): Submission<Schema>;
Expand All @@ -28,7 +28,7 @@ export function parse<Schema>(
resolve?: (
payload: Record<string, any>,
intent: string,
) => Promise<{ value?: Schema; error?: Record<string, string | string[]> }>;
) => Promise<{ value?: Schema; error?: Record<string, string[]> }>;
stripEmptyValue?: boolean;
},
): Promise<Submission<Schema>>;
Expand All @@ -39,8 +39,8 @@ export function parse<Schema>(
payload: Record<string, any>,
intent: string,
) =>
| { value?: Schema; error?: Record<string, string | string[]> }
| Promise<{ value?: Schema; error?: Record<string, string | string[]> }>;
| { value?: Schema; error?: Record<string, string[]> }
| Promise<{ value?: Schema; error?: Record<string, string[]> }>;
stripEmptyValue?: boolean;
},
): Submission<Schema> | Promise<Submission<Schema>>;
Expand All @@ -51,8 +51,8 @@ export function parse<Schema>(
payload: Record<string, any>,
intent: string,
) =>
| { value?: Schema; error?: Record<string, string | string[]> }
| Promise<{ value?: Schema; error?: Record<string, string | string[]> }>;
| { value?: Schema; error?: Record<string, string[]> }
| Promise<{ value?: Schema; error?: Record<string, string[]> }>;
stripEmptyValue?: boolean;
},
): Submission<Schema> | Promise<Submission<Schema>> {
Expand Down Expand Up @@ -83,7 +83,7 @@ export function parse<Schema>(

const result = options.resolve(submission.payload, submission.intent);
const mergeResolveResult = (resolved: {
error?: Record<string, string | string[]>;
error?: Record<string, string[]>;
value?: Schema;
}) => {
return {
Expand Down
1 change: 1 addition & 0 deletions packages/conform-dom/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"target": "ES2020",
"moduleResolution": "node16",
"allowSyntheticDefaultImports": false,
"noUncheckedIndexedAccess": true,
"strict": true,
"declaration": true,
"emitDeclarationOnly": true,
Expand Down
8 changes: 4 additions & 4 deletions packages/conform-react/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -392,16 +392,16 @@ import { parse } from '@conform-to/react';
const formData = new FormData();
const submission = parse(formData, {
resolve({ email, password }) {
const error: Record<string, string> = {};
const error: Record<string, string[]> = {};
if (typeof email !== 'string') {
error.email = 'Email is required';
error.email = ['Email is required'];
} else if (!/^[^@]+@[^@]+$/.test(email)) {
error.email = 'Email is invalid';
error.email = ['Email is invalid'];
}
if (typeof password !== 'string') {
error.password = 'Password is required';
error.password = ['Password is required'];
}
if (error.email || error.password) {
Expand Down
Loading

0 comments on commit 30a972b

Please sign in to comment.