diff --git a/src/FileUtils/AgGridUtils.js b/src/FileUtils/AgGridUtils.js index 5c56a39..cd8ea4c 100644 --- a/src/FileUtils/AgGridUtils.js +++ b/src/FileUtils/AgGridUtils.js @@ -85,39 +85,68 @@ const _getColTypeFromTypeArray = (typeArray) => { return 'string'; // Fall back to default type }; +const validateDateFormat = (value, options = {}) => { + if (typeof value !== 'string') return false; + const { dateFormat = 'yyyy-MM-dd' } = options; + + const formatRegex = dateFormat + .replace(/yyyy/, '\\d{4}') + .replace(/MM/, '(0[1-9]|1[0-2])') + .replace(/dd/, '(0[1-9]|[12]\\d|3[01])') + .replace(/\//g, '\\/') + .replace(/-/g, '-'); + + const regex = new RegExp(`^${formatRegex}$`); + return regex.test(value); +}; + const _validateFormat = (rows, hasHeader, cols, options) => { const colsData = cols.map((col) => ({ ...col, type: _getColTypeFromTypeArray(col.type) })); const errors = []; const knownColsCount = colsData.length; const startIndex = hasHeader ? 1 : 0; + + const colMeta = cols.map((col) => ({ + field: col.field, + type: _getColTypeFromTypeArray(col.type), + acceptsEmptyFields: col.acceptsEmptyFields ?? col.cellEditorParams?.acceptsEmptyFields ?? false, + colOptions: { + ...options, + enumValues: col.enumValues ?? col.cellEditorParams?.enumValues, + minValue: col.minValue, + maxValue: col.maxValue, + }, + })); + for (let rowIndex = startIndex; rowIndex < rows.length; rowIndex++) { const row = rows[rowIndex]; while (row[row.length - 1] === undefined && row.length > knownColsCount) row.pop(); - if (row.length !== knownColsCount || row.includes(undefined)) - _forgeColumnsCountError(row, rowIndex + 1, colsData, errors); - row.forEach((rowCell, colIndex) => { - if (colIndex < knownColsCount) { - const colType = colsData[colIndex].type; - if (colType && rowCell !== undefined) { - // use of cellEditorParams is deprecated - const colOptions = { - ...options, - enumValues: colsData[colIndex]?.enumValues ?? colsData[colIndex]?.cellEditorParams?.enumValues, - minValue: colsData[colIndex]?.minValue, - maxValue: colsData[colIndex]?.maxValue, - }; - const acceptsEmptyFields = - // use of cellEditorParams is deprecated - colsData[colIndex].acceptsEmptyFields ?? colsData[colIndex].cellEditorParams?.acceptsEmptyFields ?? false; - const validationResult = ValidationUtils.isValid(rowCell, colType, colOptions, acceptsEmptyFields); - if (validationResult !== true) { - const { summary: errorSummary, context: errorContext } = validationResult; - const errorLoc = `Line ${rowIndex + 1}, Column ${colIndex + 1} ("${colsData[colIndex].field}")`; - errors.push(new PanelError(errorSummary, errorLoc, errorContext)); - } - } + if (row.length !== knownColsCount || row.includes(undefined)) { + _forgeColumnsCountError(row, rowIndex + 1, cols, errors); + continue; + } + + for (let colIndex = 0; colIndex < knownColsCount; colIndex++) { + const { type, colOptions, acceptsEmptyFields, field } = colMeta[colIndex]; + const value = row[colIndex]; + if (value === undefined) continue; + + if (type === 'date' && !validateDateFormat(value, colOptions)) { + const expectedFormat = colOptions.dateFormat || 'dd/MM/yyyy'; + const errorSummary = 'Incorrect date value'; + const errorContext = `Incorrect value: "${value}" for type date\nExpected format: ${expectedFormat}`; + const errorLoc = `Line ${rowIndex + 1}, Column ${colIndex + 1} ("${field}")`; + errors.push(new PanelError(errorSummary, errorLoc, errorContext)); + continue; + } + + const validationResult = ValidationUtils.isValid(value, type, colOptions, acceptsEmptyFields); + if (validationResult !== true) { + const { summary: errorSummary, context: errorContext } = validationResult; + const errorLoc = `Line ${rowIndex + 1}, Column ${colIndex + 1} ("${field}")`; + errors.push(new PanelError(errorSummary, errorLoc, errorContext)); } - }); + } } return errors;