/* |-------------------------------------------------------------------------- | Preloaded File - node ace make:preload rules/dependentArrayMinLength |-------------------------------------------------------------------------- */ import { FieldContext } from '@vinejs/vine/types'; import vine, { VineArray } from '@vinejs/vine'; import { SchemaTypes } from '@vinejs/vine/types'; /** * Options accepted by the dependentArrayMinLength rule */ type Options = { min: number; dependentArray: string; }; async function dependentArrayMinLength(value: unknown, options: Options, field: FieldContext) { const dependentArrayValue = field.data[options.dependentArray]; // Both values can be null/undefined or arrays, but not other types const isMainValueValid = value === null || value === undefined || Array.isArray(value); const isDependentValueValid = dependentArrayValue === null || dependentArrayValue === undefined || Array.isArray(dependentArrayValue); if (!isMainValueValid || !isDependentValueValid) { field.report( `Invalid file data format. Please contact support if this error persists.`, 'array.dependentArrayMinLength', field, options, ); return false; } // Convert null/undefined to empty arrays for length checking const mainArray = Array.isArray(value) ? value : []; const dependentArray = Array.isArray(dependentArrayValue) ? dependentArrayValue : []; // Calculate total count across both arrays const totalCount = mainArray.length + dependentArray.length; // Check if minimum requirement is met if (totalCount >= options.min) { return true; } // Special case: if dependent array has items, main array can be empty/null if (dependentArray.length >= options.min && mainArray.length === 0) { return true; } // Determine appropriate error message based on context const hasExistingFiles = dependentArray.length > 0; const hasNewFiles = mainArray.length > 0; if (!hasExistingFiles && !hasNewFiles) { // No files at all field.report( `Your dataset must include at least {{ min }} file. Please upload a new file to continue.`, 'array.dependentArrayMinLength', field, options, ); } else if (hasExistingFiles && !hasNewFiles && dependentArray.length < options.min) { // Has existing files but marked for deletion, no new files field.report( `You have marked all existing files for deletion. Please upload at least {{ min }} new file or keep some existing files.`, 'array.dependentArrayMinLength', field, options, ); } else { // Generic fallback message field.report( `Your dataset must have at least {{ min }} file. You can either upload new files or keep existing ones.`, 'array.dependentArrayMinLength', field, options, ); } return false; } export const dependentArrayMinLengthRule = vine.createRule(dependentArrayMinLength); // Extend the VineArray interface declare module '@vinejs/vine' { interface VineArray { dependentArrayMinLength(options: Options): this; } } VineArray.macro('dependentArrayMinLength', function (this: VineArray, options: Options) { return this.use(dependentArrayMinLengthRule(options)); });