(
field: string,
arr: unknown,
opts: KindOpts & { min?: number; max?: number; itemNoun?: string },
)
| 193 | * for the max message. |
| 194 | */ |
| 195 | export function requireArrayLength( |
| 196 | field: string, |
| 197 | arr: unknown, |
| 198 | opts: KindOpts & { min?: number; max?: number; itemNoun?: string }, |
| 199 | ): asserts arr is unknown[] { |
| 200 | const { kind = 'field', min = 0, max, itemNoun = 'item' } = opts; |
| 201 | |
| 202 | // Structural check: must be an array. |
| 203 | const typeResult = v.safeParse(v.array(v.unknown()), arr); |
| 204 | if (!typeResult.success) { |
| 205 | throw localValidationError(field, 'is required and must be an array', undefined, kind); |
| 206 | } |
| 207 | |
| 208 | const arrVal = arr as unknown[]; |
| 209 | |
| 210 | // Lower bound. |
| 211 | if (arrVal.length < min) { |
| 212 | const minLabel = min === 1 ? `one ${itemNoun}` : `${min} ${itemNoun}s`; |
| 213 | throw localValidationError(field, `must contain at least ${minLabel}`, undefined, kind); |
| 214 | } |
| 215 | |
| 216 | // Upper bound. |
| 217 | if (max !== undefined && arrVal.length > max) { |
| 218 | throw localValidationError( |
| 219 | field, |
| 220 | `must contain at most ${max} ${itemNoun}s (got ${arrVal.length})`, |
| 221 | undefined, |
| 222 | kind, |
| 223 | ); |
| 224 | } |
| 225 | } |
no test coverage detected