🎨 Improve code readability by reformatting and updating function definitions and comments
This commit is contained in:
140
code/websites/pokedex.online/src/utilities/csv-utils.js
Normal file
140
code/websites/pokedex.online/src/utilities/csv-utils.js
Normal file
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* CSV Parsing Utilities
|
||||
* Functions for parsing and validating CSV files (RK9 player registrations)
|
||||
*/
|
||||
|
||||
import { EXPECTED_CSV_HEADERS, CSV_HEADERS } from './constants.js';
|
||||
|
||||
/**
|
||||
* Validate CSV headers against expected format
|
||||
* @param {string[]} headers - Array of header names from CSV
|
||||
* @throws {Error} If headers are invalid or missing required fields
|
||||
*/
|
||||
export function validateCsvHeaders(headers) {
|
||||
if (!headers || headers.length === 0) {
|
||||
throw new Error('CSV file is missing headers');
|
||||
}
|
||||
|
||||
if (headers.length !== EXPECTED_CSV_HEADERS.length) {
|
||||
throw new Error(
|
||||
`Invalid CSV file headers: Expected ${EXPECTED_CSV_HEADERS.length} headers but found ${headers.length}`
|
||||
);
|
||||
}
|
||||
|
||||
const missingHeaders = EXPECTED_CSV_HEADERS.filter(
|
||||
expectedHeader => !headers.includes(expectedHeader)
|
||||
);
|
||||
|
||||
if (missingHeaders.length > 0) {
|
||||
throw new Error(
|
||||
`Invalid CSV file headers: Missing the following headers: ${missingHeaders.join(', ')}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse CSV text content into structured player data
|
||||
* @param {string} csvData - Raw CSV file content
|
||||
* @returns {Object} Object keyed by screenname with player data
|
||||
* @throws {Error} If CSV format is invalid
|
||||
*/
|
||||
export function parseCsv(csvData) {
|
||||
const rows = csvData
|
||||
.split('\n')
|
||||
.map(row => row.split(','))
|
||||
.filter(row => row.some(cell => cell.trim() !== ''));
|
||||
|
||||
if (rows.length === 0) {
|
||||
throw new Error('CSV file is empty');
|
||||
}
|
||||
|
||||
const headers = rows[0].map(header => header.trim());
|
||||
validateCsvHeaders(headers);
|
||||
|
||||
// Validate row format
|
||||
for (let i = 1; i < rows.length; i++) {
|
||||
if (rows[i].length !== EXPECTED_CSV_HEADERS.length) {
|
||||
throw new Error(`Invalid row format at line ${i + 1}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse rows into objects
|
||||
return rows.slice(1).reduce((acc, row) => {
|
||||
const participant = {};
|
||||
EXPECTED_CSV_HEADERS.forEach((header, idx) => {
|
||||
participant[header] = row[idx]?.trim();
|
||||
});
|
||||
acc[participant[CSV_HEADERS.SCREENNAME]] = participant;
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse CSV file from browser File API
|
||||
* @param {File} file - File object from input[type=file]
|
||||
* @returns {Promise<Object>} Parsed player data
|
||||
*/
|
||||
export async function parsePlayerCsvFile(file) {
|
||||
if (!file) {
|
||||
throw new Error('No file provided');
|
||||
}
|
||||
|
||||
if (!file.name.endsWith('.csv')) {
|
||||
throw new Error('File must be a CSV file');
|
||||
}
|
||||
|
||||
const text = await file.text();
|
||||
return parseCsv(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert parsed CSV data to array format
|
||||
* @param {Object} csvObject - Object from parseCsv
|
||||
* @returns {Array} Array of player objects with screenname included
|
||||
*/
|
||||
export function csvObjectToArray(csvObject) {
|
||||
return Object.entries(csvObject).map(([screenname, data]) => ({
|
||||
...data,
|
||||
screenname
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate individual player data
|
||||
* @param {Object} player - Player data object
|
||||
* @returns {Object} Validation result {valid: boolean, errors: string[]}
|
||||
*/
|
||||
export function validatePlayerData(player) {
|
||||
const errors = [];
|
||||
|
||||
if (!player[CSV_HEADERS.PLAYER_ID]) {
|
||||
errors.push('Missing player_id');
|
||||
}
|
||||
|
||||
if (!player[CSV_HEADERS.SCREENNAME]) {
|
||||
errors.push('Missing screenname');
|
||||
}
|
||||
|
||||
if (!player[CSV_HEADERS.DIVISION]) {
|
||||
errors.push('Missing division');
|
||||
}
|
||||
|
||||
const email = player[CSV_HEADERS.EMAIL];
|
||||
if (email && !isValidEmail(email)) {
|
||||
errors.push('Invalid email format');
|
||||
}
|
||||
|
||||
return {
|
||||
valid: errors.length === 0,
|
||||
errors
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple email validation
|
||||
* @param {string} email - Email address to validate
|
||||
* @returns {boolean} True if email format is valid
|
||||
*/
|
||||
function isValidEmail(email) {
|
||||
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
|
||||
}
|
||||
Reference in New Issue
Block a user