if (rows.length < 2) { thrownewError("CSV file does not contain enough data"); }
// Get headers from the first line, normalize them to avoid issues with spaces or case constheaders = rows[0].map((header) =>header.trim().toLowerCase());
// Validate required headers constrequiredHeaders = ["title"]; for (constrequiredofrequiredHeaders) { if (!headers.includes(required)) { thrownewError(`CSV is missing required header: ${required}`); } }
// Parse manga entries constmanga: KenmeiManga[] = [];
// Skip the header row for (leti = 1; i < rows.length; i++) { constvalues = rows[i];
// Skip rows that don't have enough fields (likely incomplete/malformed data) if (values.length < 2) { console.warn( `Skipping row ${i+1} with insufficient fields: ${values.join(",")}`, ); continue; }
// Skip rows where the title is just a number or looks like a chapter reference constpotentialTitle = values[headers.indexOf("title")]; if ( /^(Chapter|Ch\.|Vol\.|Volume) \d+$/i.test(potentialTitle) || /^\d+$/.test(potentialTitle) ) { console.warn( `Skipping row ${i+1} with invalid title: "${potentialTitle}"`, ); continue; }
// Create an object mapping headers to values constentry: Record<string, string> = {}; headers.forEach((header, index) => { if (index < values.length) { entry[header] = values[index]; } });
// Find values using flexible column names constfindValue = (mappings: string[]): string | undefined=> { for (constmappingofmappings) { if (entry[mapping] !== undefined) { returnentry[mapping]; } } returnundefined; };
// Parse numeric values safely constparseIntSafe = (value: string | undefined): number | undefined=> { if (!value) returnundefined; // Remove any non-numeric characters except decimal point constcleanValue = value.replace(/[^\d.]/g, ""); if (!cleanValue) returnundefined; constparsed = parseInt(cleanValue, 10); returnisNaN(parsed) ? undefined : parsed; };
// Process in batches if needed and validation is enabled if (parseOptions.validateStructure) { constresult = processKenmeiMangaBatches(manga, 100, parseOptions);
if ( result.validationErrors.length > 0 && !parseOptions.allowPartialData ) { thrownewError( `${result.validationErrors.length} validation errors found in CSV import`, ); }
// Use the processed entries if we have them if (result.processedEntries.length > 0) { manga.length = 0; // Clear the array manga.push(...result.processedEntries); } }
Parse a Kenmei CSV export file.
Source