diff --git a/packages/payload/src/fields/config/types.ts b/packages/payload/src/fields/config/types.ts index 4f723e9eb..01b9edcaa 100644 --- a/packages/payload/src/fields/config/types.ts +++ b/packages/payload/src/fields/config/types.ts @@ -104,9 +104,33 @@ import type { } from '../../config/types.js' import type { DBIdentifierName } from '../../database/types.js' import type { SanitizedGlobalConfig } from '../../globals/config/types.js' -import type { CollectionSlug } from '../../index.js' +import type { + ArrayFieldValidation, + BlocksFieldValidation, + CheckboxFieldValidation, + CodeFieldValidation, + CollectionSlug, + DateFieldValidation, + EmailFieldValidation, + JSONFieldValidation, + PointFieldValidation, + RadioFieldValidation, + TextareaFieldValidation, +} from '../../index.js' import type { DocumentPreferences } from '../../preferences/types.js' import type { Operation, PayloadRequest, RequestContext, Where } from '../../types/index.js' +import type { + NumberFieldManyValidation, + NumberFieldSingleValidation, + RelationshipFieldManyValidation, + RelationshipFieldSingleValidation, + SelectFieldManyValidation, + SelectFieldSingleValidation, + TextFieldManyValidation, + TextFieldSingleValidation, + UploadFieldManyValidation, + UploadFieldSingleValidation, +} from '../validations.js' export type FieldHookArgs = { /** The collection which the field belongs to. If the field belongs to a global, this will be null. */ @@ -335,7 +359,7 @@ export type Validate< TSiblingData = any, TFieldConfig extends object = object, > = ( - value: TValue, + value: null | TValue | undefined, options: ValidateOptions, ) => Promise | string | true @@ -452,7 +476,7 @@ export type NumberField = { maxRows?: number /** Minimum number of numbers in the numbers array, if `hasMany` is set to true. */ minRows?: number - validate?: Validate + validate?: NumberFieldManyValidation } | { /** Makes this field an ordered array of numbers instead of just a single number. */ @@ -461,7 +485,7 @@ export type NumberField = { maxRows?: undefined /** Minimum number of numbers in the numbers array, if `hasMany` is set to true. */ minRows?: undefined - validate?: Validate + validate?: NumberFieldSingleValidation } ) & Omit @@ -502,7 +526,7 @@ export type TextField = { maxRows?: number /** Minimum number of strings in the strings array, if `hasMany` is set to true. */ minRows?: number - validate?: Validate + validate?: TextFieldManyValidation } | { /** Makes this field an ordered array of strings instead of just a single string. */ @@ -511,7 +535,7 @@ export type TextField = { maxRows?: undefined /** Minimum number of strings in the strings array, if `hasMany` is set to true. */ minRows?: undefined - validate?: Validate + validate?: TextFieldSingleValidation } ) & Omit @@ -541,7 +565,7 @@ export type EmailField = { placeholder?: Record | string } & Admin type: 'email' - validate?: Validate + validate?: EmailFieldValidation } & Omit export type EmailFieldClient = { @@ -572,7 +596,7 @@ export type TextareaField = { maxLength?: number minLength?: number type: 'textarea' - validate?: Validate + validate?: TextareaFieldValidation } & Omit export type TextareaFieldClient = { @@ -598,7 +622,7 @@ export type CheckboxField = { } & Admin['components'] } & Admin type: 'checkbox' - validate?: Validate + validate?: CheckboxFieldValidation } & Omit export type CheckboxFieldClient = { @@ -625,7 +649,7 @@ export type DateField = { placeholder?: Record | string } & Admin type: 'date' - validate?: Validate + validate?: DateFieldValidation } & Omit export type DateFieldClient = { @@ -861,7 +885,7 @@ type SharedUploadProperties = { */ min?: number minRows?: number - validate?: Validate + validate?: UploadFieldManyValidation } | { hasMany?: false | undefined @@ -875,7 +899,7 @@ type SharedUploadProperties = { */ min?: undefined minRows?: undefined - validate?: Validate + validate?: UploadFieldSingleValidation } ) & Omit @@ -950,7 +974,7 @@ export type CodeField = { maxLength?: number minLength?: number type: 'code' - validate?: Validate + validate?: CodeFieldValidation } & Omit export type CodeFieldClient = { @@ -983,7 +1007,7 @@ export type JSONField = { uri: string } type: 'json' - validate?: Validate, unknown, unknown, JSONField> + validate?: JSONFieldValidation } & Omit export type JSONFieldClient = { @@ -1024,11 +1048,11 @@ export type SelectField = { } & ( | { hasMany: true - validate?: Validate + validate?: SelectFieldManyValidation } | { hasMany?: false | undefined - validate?: Validate + validate?: SelectFieldSingleValidation } ) & Omit @@ -1068,7 +1092,7 @@ type SharedRelationshipProperties = { */ min?: number minRows?: number - validate?: Validate + validate?: RelationshipFieldManyValidation } | { hasMany?: false | undefined @@ -1082,7 +1106,7 @@ type SharedRelationshipProperties = { */ min?: undefined minRows?: undefined - validate?: Validate + validate?: RelationshipFieldSingleValidation } ) & Omit @@ -1155,11 +1179,11 @@ export function valueIsValueWithRelation(value: unknown): value is ValueWithRela return value !== null && typeof value === 'object' && 'relationTo' in value && 'value' in value } -export type RelationshipValue = - | (number | string)[] - | (number | string) - | ValueWithRelation - | ValueWithRelation[] +export type RelationshipValue = RelationshipValueMany | RelationshipValueSingle + +export type RelationshipValueMany = (number | string)[] | ValueWithRelation[] + +export type RelationshipValueSingle = number | string | ValueWithRelation export type RichTextField< TValue extends object = any, @@ -1231,7 +1255,7 @@ export type ArrayField = { maxRows?: number minRows?: number type: 'array' - validate?: Validate + validate?: ArrayFieldValidation } & Omit export type ArrayFieldClient = { @@ -1266,7 +1290,7 @@ export type RadioField = { enumName?: DBIdentifierName options: Option[] type: 'radio' - validate?: Validate + validate?: RadioFieldValidation } & Omit export type RadioFieldClient = { @@ -1352,7 +1376,7 @@ export type BlocksField = { maxRows?: number minRows?: number type: 'blocks' - validate?: Validate + validate?: BlocksFieldValidation } & Omit export type BlocksFieldClient = { @@ -1379,7 +1403,7 @@ export type PointField = { step?: number } & Admin type: 'point' - validate?: Validate<[number, number], unknown, unknown, PointField> + validate?: PointFieldValidation } & Omit export type PointFieldClient = { diff --git a/packages/payload/src/fields/validations.ts b/packages/payload/src/fields/validations.ts index 45e7cd86e..49a9321bd 100644 --- a/packages/payload/src/fields/validations.ts +++ b/packages/payload/src/fields/validations.ts @@ -20,6 +20,8 @@ import type { RadioField, RelationshipField, RelationshipValue, + RelationshipValueMany, + RelationshipValueSingle, RichTextField, SelectField, TextareaField, @@ -32,6 +34,11 @@ import { isNumber } from '../utilities/isNumber.js' import { isValidID } from '../utilities/isValidID.js' export type TextFieldValidation = Validate + +export type TextFieldManyValidation = Validate + +export type TextFieldSingleValidation = Validate + export const text: TextFieldValidation = ( value, { @@ -93,6 +100,7 @@ export const text: TextFieldValidation = ( } export type PasswordFieldValidation = Validate + export const password: PasswordFieldValidation = ( value, { @@ -135,6 +143,7 @@ export type ConfirmPasswordFieldValidation = Validate< { password: string }, TextField > + export const confirmPassword: ConfirmPasswordFieldValidation = ( value, { req: { t }, required, siblingData }, @@ -151,6 +160,7 @@ export const confirmPassword: ConfirmPasswordFieldValidation = ( } export type EmailFieldValidation = Validate + export const email: EmailFieldValidation = ( value, { @@ -185,6 +195,7 @@ export const email: EmailFieldValidation = ( } export type UsernameFieldValidation = Validate + export const username: UsernameFieldValidation = ( value, { @@ -229,6 +240,7 @@ export const username: UsernameFieldValidation = ( } export type TextareaFieldValidation = Validate + export const textarea: TextareaFieldValidation = ( value, { @@ -265,6 +277,7 @@ export const textarea: TextareaFieldValidation = ( } export type CodeFieldValidation = Validate + export const code: CodeFieldValidation = (value, { req: { t }, required }) => { if (required && value === undefined) { return t('validation:required') @@ -279,6 +292,7 @@ export type JSONFieldValidation = Validate< unknown, { jsonError?: string } & JSONField > + export const json: JSONFieldValidation = async ( value, { jsonError, jsonSchema, req: { t }, required }, @@ -348,6 +362,7 @@ export const json: JSONFieldValidation = async ( } export type CheckboxFieldValidation = Validate + export const checkbox: CheckboxFieldValidation = (value, { req: { t }, required }) => { if ((value && typeof value !== 'boolean') || (required && typeof value !== 'boolean')) { return t('validation:trueOrFalse') @@ -357,6 +372,7 @@ export const checkbox: CheckboxFieldValidation = (value, { req: { t }, required } export type DateFieldValidation = Validate + export const date: DateFieldValidation = (value, { req: { t }, required }) => { if (value && !isNaN(Date.parse(value.toString()))) { return true @@ -374,6 +390,7 @@ export const date: DateFieldValidation = (value, { req: { t }, required }) => { } export type RichTextFieldValidation = Validate + export const richText: RichTextFieldValidation = async (value, options) => { if (!options?.editor) { throw new Error('richText field has no editor property.') @@ -420,6 +437,11 @@ const validateArrayLength = ( } export type NumberFieldValidation = Validate + +export type NumberFieldManyValidation = Validate + +export type NumberFieldSingleValidation = Validate + export const number: NumberFieldValidation = ( value, { hasMany, max, maxRows, min, minRows, req: { t }, required }, @@ -611,6 +633,10 @@ const validateFilterOptions: Validate< export type UploadFieldValidation = Validate +export type UploadFieldManyValidation = Validate + +export type UploadFieldSingleValidation = Validate + export const upload: UploadFieldValidation = async (value, options) => { const { maxRows, @@ -694,6 +720,21 @@ export type RelationshipFieldValidation = Validate< unknown, RelationshipField > + +export type RelationshipFieldManyValidation = Validate< + RelationshipValueMany, + unknown, + unknown, + RelationshipField +> + +export type RelationshipFieldSingleValidation = Validate< + RelationshipValueSingle, + unknown, + unknown, + RelationshipField +> + export const relationship: RelationshipFieldValidation = async (value, options) => { const { maxRows, @@ -772,6 +813,11 @@ export const relationship: RelationshipFieldValidation = async (value, options) } export type SelectFieldValidation = Validate + +export type SelectFieldManyValidation = Validate + +export type SelectFieldSingleValidation = Validate + export const select: SelectFieldValidation = ( value, { hasMany, options, req: { t }, required }, @@ -810,6 +856,7 @@ export const select: SelectFieldValidation = ( } export type RadioFieldValidation = Validate + export const radio: RadioFieldValidation = (value, { options, req: { t }, required }) => { if (value) { const valueMatchesOption = options.some( @@ -827,6 +874,7 @@ export type PointFieldValidation = Validate< unknown, PointField > + export const point: PointFieldValidation = (value = ['', ''], { req: { t }, required }) => { const lng = parseFloat(String(value[0])) const lat = parseFloat(String(value[1])) diff --git a/packages/payload/src/index.ts b/packages/payload/src/index.ts index ce898f418..a614dd10f 100644 --- a/packages/payload/src/index.ts +++ b/packages/payload/src/index.ts @@ -937,15 +937,25 @@ export type { DateFieldValidation, EmailFieldValidation, JSONFieldValidation, + NumberFieldManyValidation, + NumberFieldSingleValidation, NumberFieldValidation, PasswordFieldValidation, PointFieldValidation, RadioFieldValidation, + RelationshipFieldManyValidation, + RelationshipFieldSingleValidation, RelationshipFieldValidation, RichTextFieldValidation, + SelectFieldManyValidation, + SelectFieldSingleValidation, SelectFieldValidation, TextareaFieldValidation, + TextFieldManyValidation, + TextFieldSingleValidation, TextFieldValidation, + UploadFieldManyValidation, + UploadFieldSingleValidation, UploadFieldValidation, UsernameFieldValidation, } from './fields/validations.js' diff --git a/test/fields/collections/Number/index.ts b/test/fields/collections/Number/index.ts index 55fb07f49..be81b643c 100644 --- a/test/fields/collections/Number/index.ts +++ b/test/fields/collections/Number/index.ts @@ -60,7 +60,7 @@ const NumberFields: CollectionConfig = { name: 'validatesHasMany', type: 'number', hasMany: true, - validate: (value: number[]) => { + validate: (value) => { if (value && !Array.isArray(value)) { return 'value should be an array' }