feat: csv-loader?
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
import type { LoaderContext } from '@rspack/core';
|
||||
import { parse } from 'csv-parse/sync';
|
||||
import { parseSchema, createValidator, parseValue } from '../index.js';
|
||||
|
||||
export interface CsvLoaderOptions {
|
||||
delimiter?: string;
|
||||
quote?: string;
|
||||
escape?: string;
|
||||
}
|
||||
|
||||
interface PropertyConfig {
|
||||
name: string;
|
||||
schema: any;
|
||||
validator: (value: unknown) => boolean;
|
||||
parser: (valueString: string) => unknown;
|
||||
}
|
||||
|
||||
export default function csvLoader(
|
||||
this: LoaderContext<CsvLoaderOptions>,
|
||||
content: string
|
||||
): string {
|
||||
const options = this.getOptions() || {};
|
||||
const delimiter = options.delimiter ?? ',';
|
||||
const quote = options.quote ?? '"';
|
||||
const escape = options.escape ?? '\\';
|
||||
|
||||
const records = parse(content, {
|
||||
delimiter,
|
||||
quote,
|
||||
escape,
|
||||
relax_column_count: true,
|
||||
});
|
||||
|
||||
if (records.length < 2) {
|
||||
throw new Error('CSV must have at least 2 rows: headers and schemas');
|
||||
}
|
||||
|
||||
const headers = records[0];
|
||||
const schemas = records[1];
|
||||
|
||||
if (headers.length !== schemas.length) {
|
||||
throw new Error(
|
||||
`Header count (${headers.length}) does not match schema count (${schemas.length})`
|
||||
);
|
||||
}
|
||||
|
||||
const propertyConfigs: PropertyConfig[] = headers.map((header: string, index: number) => {
|
||||
const schemaString = schemas[index];
|
||||
const schema = parseSchema(schemaString);
|
||||
return {
|
||||
name: header,
|
||||
schema,
|
||||
validator: createValidator(schema),
|
||||
parser: (valueString: string) => parseValue(schema, valueString),
|
||||
};
|
||||
});
|
||||
|
||||
const dataRows = records.slice(2);
|
||||
const objects = dataRows.map((row: string[], rowIndex: number) => {
|
||||
const obj: Record<string, unknown> = {};
|
||||
propertyConfigs.forEach((config, colIndex) => {
|
||||
const rawValue = row[colIndex] ?? '';
|
||||
try {
|
||||
const parsed = config.parser(rawValue);
|
||||
if (!config.validator(parsed)) {
|
||||
throw new Error(
|
||||
`Validation failed for property "${config.name}" at row ${rowIndex + 3}: ${rawValue}`
|
||||
);
|
||||
}
|
||||
obj[config.name] = parsed;
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
throw new Error(
|
||||
`Failed to parse property "${config.name}" at row ${rowIndex + 3}, column ${colIndex + 1}: ${error.message}`
|
||||
);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
return obj;
|
||||
});
|
||||
|
||||
const json = JSON.stringify(objects, null, 2);
|
||||
return `export default ${json};`;
|
||||
}
|
||||
Reference in New Issue
Block a user