UNPKG

file-validation-engine

Version:

A dynamic rule-based validation engine for Excel and CSV files

70 lines (63 loc) 3.41 kB
import { RuleEngine, Rule } from './RuleEngine'; import fs from 'fs'; // Rule configuration array const ruleConfigs: Array<any> = [ { column: 'id', type: 'integer', nullable: false, unique: true }, // Example: id must be unique { column: 'price', type: 'number', maxDecimals: 3, nullable: true }, { column: 'name', type: 'string', max: 20, nullable: false, allowEmpty: false }, { column: 'description', type: 'string', nullable: true, allowEmpty: true }, { column: 'email', type: 'string', allowEmpty: true, customValidate: (value: string) => /.+@.+\..+/.test(value), errorMessage: 'must be a valid email format', condition: (row: any) => row['email'] !== '' }, { column: 'status', type: 'string', customValidate: (value: string, row: any) => value === 'active' || row['age'] > 18, errorMessage: 'must be active if age > 18' }, ]; function makeRule(config: any): Rule { return { column: config.column, unique: config.unique, // <-- Add unique support validate: (value: any, row: any) => { if (config.nullable && (value === null || value === undefined)) return true; if (config.allowEmpty && value === '') return true; if (config.customValidate) return config.customValidate(value, row); if (config.type === 'integer') return Number.isInteger(Number(value)); if (config.type === 'number') { if (isNaN(Number(value))) return false; if (config.maxDecimals !== undefined) { const parts = value.toString().split('.'); if (parts[1] && parts[1].length > config.maxDecimals) return false; } return true; } if (config.type === 'string') { if (typeof value === 'number' || Number.isInteger(Number(value))) return true; if (typeof value !== 'string') return false; if (config.max && value.length > config.max) return false; if (config.allowEmpty === false && value === '') return false; return true; } if (config.type === 'date') return value === null || !isNaN(Date.parse(value)); return true; }, errorMessage: config.errorMessage || makeErrorMessage(config), condition: config.condition }; } function makeErrorMessage(config: any) { let msg = 'must be'; if (config.nullable) msg += ' null or'; if (config.allowEmpty) msg += ' empty or'; if (config.type === 'integer') msg += ' an integer'; if (config.type === 'number') msg += ' a number'; if (config.maxDecimals !== undefined) msg += ` (max ${config.maxDecimals} decimals)`; if (config.type === 'string') msg += ' a string'; if (config.max) msg += ` (max ${config.max} chars)`; if (config.allowEmpty === false) msg += ' and not empty'; return msg.trim(); } const rules: Rule[] = ruleConfigs.map(makeRule); const engine = new RuleEngine(rules, { chunkSize: 5000 }); (async () => { const inputFile = 'input.csv'; // or 'input.xlsx' const errorFile = 'validation_error.txt'; if (fs.existsSync(errorFile)) fs.unlinkSync(errorFile); await engine.validateFile(inputFile, errorFile); console.log('Validation complete. Errors written to', errorFile); })();