Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion demo/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ interface UserFormFields {
firstName: string;
lastName: string;
email: string;
tShirtSize: string;
}

function getErrorText(formField: FormField, formFields: FormFields, submitting?: boolean) {
Expand All @@ -19,6 +20,8 @@ function getErrorText(formField: FormField, formFields: FormFields, submitting?:
return 'Required';
case 'isEmail':
return 'Invalid email';
case 'isOneOf':
return 'Must be small, medium, or large';
}
}

Expand All @@ -42,14 +45,24 @@ const formFieldConfigs: FormFieldConfig[] = [
isEmail: true,
getHelperText: getErrorText,
},
{
name: 'tShirtSize',
label: 'T-shirt size',
required: true,
isOneOf: ['small', 'medium', 'large'],
getHelperText: getErrorText,
},
];

export class Home extends React.Component {
render() {
return (
<Page>
<ClassyForm formFieldConfigs={formFieldConfigs}>
{({ formFields: { email, firstName, lastName }, onSubmit }: FormsContextContext<UserFormFields>) => {
{({
formFields: { email, firstName, lastName, tshirtSize },
onSubmit,
Comment on lines +63 to +64
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P0 tshirtSize casing mismatch causes runtime crash

The field is configured in formFieldConfigs with name: 'tShirtSize' (capital S) and declared in UserFormFields as tShirtSize, but it is destructured here as tshirtSize (lowercase s). Because the key does not exist in formFields, tshirtSize will be undefined at runtime. Accessing tshirtSize.name on line 75 will then throw a TypeError.

Fix the destructured name to match the registered field name:

Suggested change
formFields: { email, firstName, lastName, tshirtSize },
onSubmit,
formFields: { email, firstName, lastName, tShirtSize },

Also update lines 75–79 to reference tShirtSize instead of tshirtSize.

}: FormsContextContext<UserFormFields>) => {
return (
<React.Fragment>
<FormInput key={firstName.name} formField={firstName} />
Expand All @@ -58,6 +71,13 @@ export class Home extends React.Component {

<FormInput key={email.name} formField={email} />

<FormInput
key={tshirtSize.name}
formField={tshirtSize}
autoComplete="off"
Comment on lines 71 to +77
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correctness: The destructured field is tshirtSize (camelCase, no capital S) but the UserFormFields interface defines it as tShirtSize (capital S), and the formFieldConfigs array also uses tShirtSize. This means tshirtSize will be undefined at runtime, causing a crash when accessing tshirtSize.name.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In demo/pages/index.tsx, lines 71-77, the variable `tshirtSize` is used but the interface `UserFormFields` defines the field as `tShirtSize` (capital S). The destructuring on the render method also uses `tshirtSize` (lowercase s) which won't match the actual field key. Fix the destructuring from `tshirtSize` to `tShirtSize` and update all references in these lines to `tShirtSize`.

Comment on lines 71 to +77
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correctness: The destructured field is tshirtSize (camelCase, no capital S) but the UserFormFields interface defines it as tShirtSize (capital S), and the formFieldConfigs array also uses tShirtSize. This means tshirtSize will be undefined at runtime, causing a crash when accessing tshirtSize.name.

Affected Locations:

  • demo/pages/index.tsx:71-77
  • demo/pages/index.tsx:11-14
  • demo/pages/index.tsx:46-46
🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In demo/pages/index.tsx, lines 71-77, the variable `tshirtSize` is used but the interface `UserFormFields` defines the field as `tShirtSize` (capital S). The destructuring on the render method also uses `tshirtSize` (lowercase s) which won't match the actual field key. Fix the destructuring from `tshirtSize` to `tShirtSize` and update all references in these lines to `tShirtSize`.

placeholder="small, medium, or large"
Comment on lines 72 to +78
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correctness: The destructured field is tshirtSize but the UserFormFields interface and formFieldConfigs define it as tShirtSize (camelCase with capital S). This will be undefined at runtime, causing a crash when accessing tshirtSize.name.

Affected Locations:

  • demo/pages/index.tsx:72-78
  • demo/pages/index.tsx:11-11
  • demo/pages/index.tsx:48-48
🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In demo/pages/index.tsx, lines 72-78, the variable `tshirtSize` is used but the UserFormFields interface and formFieldConfigs define it as `tShirtSize` (capital S). Fix the destructuring in the render method from `tshirtSize` to `tShirtSize` and update all usages of `tshirtSize` in this block to `tShirtSize` to match the interface definition and avoid a runtime crash.

Comment on lines 72 to +78
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correctness: The destructured field is tshirtSize but the UserFormFields interface and formFieldConfigs use tShirtSize (camelCase with capital S) — this will resolve to undefined at runtime, causing a crash when accessing tshirtSize.name.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In demo/pages/index.tsx, lines 72-78, the FormInput for t-shirt size uses `tshirtSize` but the UserFormFields interface declares `tShirtSize` (capital S). Fix the destructuring in the ClassyForm render prop from `tshirtSize` to `tShirtSize` and update the key and formField props accordingly to avoid a runtime crash.

Comment on lines 72 to +78
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correctness: The destructured field is tshirtSize but the UserFormFields interface and formFieldConfigs use tShirtSize (camelCase with capital S) — this will resolve to undefined at runtime, causing a crash when accessing tshirtSize.name.

Affected Locations:

  • demo/pages/index.tsx:72-78
  • demo/pages/index.tsx:46-46
🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In demo/pages/index.tsx, lines 72-78, the FormInput for t-shirt size uses `tshirtSize` but the UserFormFields interface declares `tShirtSize` (capital S). Fix the destructuring in the ClassyForm render prop from `tshirtSize` to `tShirtSize` and update the key and formField props accordingly to avoid a runtime crash.

/>

<div className="form-actions">
<Button variant="contained" color="primary" type="submit">
Register
Expand Down
2 changes: 2 additions & 0 deletions src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export type ErrorType =
| 'matchRegexp'
| 'maxLength'
| 'minLength'
| 'isOneOf'
| 'required'
| 'isValid'
| 'isInitError';
Expand Down Expand Up @@ -83,6 +84,7 @@ export interface FormFieldConfig {
matchRegexp?: RegExp;
maxLength?: number;
minLength?: number;
isOneOf?: Value[];

isValid?(formField: FormField, formFields: FormFields, submitting?: boolean): boolean;
getHelperText?(formField: FormField, formFields: FormFields, submitting?: boolean): string | undefined;
Expand Down
3 changes: 3 additions & 0 deletions src/validations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,7 @@ export const validations = {
minLength(formField: FormField, formFields: FormFields, submitting: boolean, length: number) {
return !isExisty(formField.value) || isEmpty(formField.value) || formField.value.length >= length;
},
isOneOf(formField: FormField, formFields: FormFields, submitting: boolean, allowedValues: Value[]) {
return !isExisty(formField.value) || isEmpty(formField.value) || allowedValues.includes(formField.value);
},
Comment on lines +98 to +100
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correctness: The new isOneOf validation is never invoked in FormsProvider.tsx's isValid function, so even if a formFieldConfig.isOneOf is configured, it will silently be ignored and no validation error will be pushed.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In src/FormsProvider.tsx, inside the `isValid` function, add a call to `validations.isOneOf` similar to the other validations. After the `minLength` block (around line 434), add:

```typescript
if (formFieldConfig.isOneOf && !validations.isOneOf(formField, formFields, submitting, formFieldConfig.isOneOf)) {
  errors.push('isOneOf');
}

Also ensure FormFieldConfig interface includes an isOneOf?: Value[] property.


</details>
<!-- ai_prompt_end -->

Comment on lines +98 to +100
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correctness: The new isOneOf validation is never invoked in FormsProvider.tsx's isValid function, unlike every other validation rule — meaning formFieldConfig.isOneOf will never be evaluated and validation will silently pass.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In `src/FormsProvider.tsx`, inside the `isValid` function, add a call to `validations.isOneOf` after the `minLength` block (around line 434), following the same pattern as the other validations:

```ts
if (formFieldConfig.isOneOf && !validations.isOneOf(formField, formFields, submitting, formFieldConfig.isOneOf)) {
  errors.push('isOneOf');
}

Also ensure FormFieldConfig includes an isOneOf property typed as Value[] | undefined.


</details>
<!-- ai_prompt_end -->

Comment on lines +98 to +100
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P0 isOneOf validator is never invoked — validation is completely non-functional

validations.isOneOf is defined here, but the isValid() function in src/FormsProvider.tsx (lines 344–443) contains an explicit if block for every other validation rule and has no corresponding check for isOneOf. Because FormsProvider.tsx is the only place validations are dispatched, any field configured with isOneOf will silently pass validation regardless of its value.

The following block must be added to isValid() in src/FormsProvider.tsx, alongside the other validator checks:

  if (
    formFieldConfig.isOneOf &&
    !validations.isOneOf(formField, formFields, submitting, formFieldConfig.isOneOf)
  ) {
    errors.push('isOneOf');
  }

Without this change, the entire feature introduced by this PR has no effect at runtime.

};