@elevate_security/customer-data-validators
Advanced tools
Comparing version 0.0.8 to 0.0.9
{ | ||
"name": "@elevate_security/customer-data-validators", | ||
"version": "0.0.8", | ||
"version": "0.0.9", | ||
"description": "", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
@@ -5,166 +5,170 @@ const Papa = require('papaparse') | ||
async function CSVFileValidator(content, config) { | ||
let emptyRowCount = 0 | ||
let line_number = 0 | ||
const rowStatus = {} | ||
const uniqueIndexes = buildIndexes(config) | ||
const errors = [] | ||
function addError(type, code, message, row=0) { | ||
errors.push(DataError(type, code, message, row)) | ||
} | ||
function addErrors(errorList) { | ||
errorList.forEach(e=>errors.push(e)) | ||
return errorList.length | ||
} | ||
function checkUniqueValues(row) { | ||
let lineErrors = [] | ||
uniqueIndexes.forEach(idx=>{ | ||
if (idx.headerName in row.data) { | ||
lineErrors = lineErrors.concat(idx.addValue(row.data[idx.headerName], line_number)) | ||
} // else no value if provided, null values don't impact unique indexes | ||
}) | ||
return lineErrors | ||
} | ||
function checkForRowErrors(row) { | ||
return checkUniqueValues(row).concat(checkForBlankValues(row), checkTypes(row), checkConstraints(row)) | ||
} | ||
function checkForBlankValues(row) { | ||
let lineErrors = [] | ||
Object.keys(config.headers).filter(h=>config.headers[h].not_blank===true).forEach(h=> { | ||
if (!(h in row.data) || row.data[h]==='') { | ||
lineErrors.push(DataError('Error', 'BlankValue', `"${h}" cannot be blank`, line_number)) | ||
} | ||
}) | ||
return lineErrors | ||
} | ||
function checkTypes(row) { | ||
let lineErrors = [] | ||
Object.keys(config.headers).filter(h=>config.headers[h].type!==undefined && config.headers[h].type!=='string' ).forEach(h=> { | ||
if (h in row.data && row.data[h]!=='') { | ||
const {isValid, message} = TYPE_VALIDATOR[config.headers[h].type].validate(row.data[h], config.headers[h]) | ||
if (!isValid) { | ||
lineErrors.push(DataError('Error', 'TypeMismatch', `"${row.data[h]}" is not a valid ${config.headers[h].type} value for "${h}": ${message}`, line_number)) | ||
} | ||
} | ||
}) | ||
return lineErrors | ||
} | ||
function checkConstraints(row) { | ||
let lineErrors = [] | ||
if (config.constraints && Array.isArray(config.constraints)) { | ||
config.constraints.forEach(c=>{ | ||
const {isValid, message} = CONSTRAINT_CLASS[c.type].check(row, c) | ||
if (!isValid) { | ||
lineErrors.push(DataError('Error', c.type, message, line_number)) | ||
} | ||
}) | ||
} | ||
return lineErrors | ||
} | ||
function checkHeaders(fields) { | ||
const reject_additional_headers = config.reject_additional_headers === true | ||
Object.keys(config.headers).filter(h=>config.headers[h].required).forEach(h => { | ||
if (!fields.includes(h)) { | ||
addError('Error','MissingHeader',`Missing mandatory column header "${h}"`) | ||
} | ||
}) | ||
if (reject_additional_headers) { | ||
fields.filter(f=>!(f in config.headers)).forEach(f=>{ | ||
addError('Error', 'InvalidHeader', `"${f}" is not a valid header`) | ||
}) | ||
} | ||
} | ||
let meta | ||
// Parse local CSV file | ||
await new Promise(resolve => Papa.parse(content, { | ||
worker: true, | ||
delimiter: ',', | ||
header: true, | ||
skipEmptyLines: false, | ||
step: function(row) { | ||
if (row.meta) meta=row.meta | ||
line_number++ | ||
if (_isNotEmptyRow(row)) { | ||
const lineErrors = row.errors.length ? row.errors : checkForRowErrors(row) | ||
if (lineErrors.length) { | ||
lineErrors.forEach(e => rowStatus[e.row] = false) | ||
addErrors(lineErrors) | ||
} else { | ||
rowStatus[line_number] = true | ||
} | ||
} else { | ||
emptyRowCount++ | ||
if (row.errors.length) { | ||
addErrors(row.errors) | ||
} else { | ||
addError('Warning', 'EmptyValues', 'Line contains no values', line_number) | ||
} | ||
} | ||
}, | ||
complete: function() { | ||
resolve() | ||
} | ||
})) | ||
checkHeaders(meta.fields) | ||
const validRowCount = Object.values(rowStatus).filter(Boolean).length | ||
let invalidRowCount = Object.keys(rowStatus).length - validRowCount | ||
Object.assign(meta, {validRowCount, emptyRowCount, invalidRowCount}) | ||
return { | ||
errors, | ||
meta | ||
} | ||
function CSVFileValidator(content, config) { | ||
return "hello" | ||
} | ||
function _isEmpty(val) { | ||
return val==='' | ||
} | ||
function _isNotEmptyRow(row) { | ||
return row.data && Object.keys(row.data).length>0 && !Object.values(row.data).every(_isEmpty) | ||
} | ||
// async function CSVFileValidator(content, config) { | ||
// let emptyRowCount = 0 | ||
// let line_number = 0 | ||
// const rowStatus = {} | ||
// const uniqueIndexes = buildIndexes(config) | ||
// const errors = [] | ||
// function addError(type, code, message, row=0) { | ||
// errors.push(DataError(type, code, message, row)) | ||
// } | ||
// function addErrors(errorList) { | ||
// errorList.forEach(e=>errors.push(e)) | ||
// return errorList.length | ||
// } | ||
// function checkUniqueValues(row) { | ||
// let lineErrors = [] | ||
// uniqueIndexes.forEach(idx=>{ | ||
// if (idx.headerName in row.data) { | ||
// lineErrors = lineErrors.concat(idx.addValue(row.data[idx.headerName], line_number)) | ||
// } // else no value if provided, null values don't impact unique indexes | ||
// }) | ||
// return lineErrors | ||
// } | ||
// function checkForRowErrors(row) { | ||
// return checkUniqueValues(row).concat(checkForBlankValues(row), checkTypes(row), checkConstraints(row)) | ||
// } | ||
// function checkForBlankValues(row) { | ||
// let lineErrors = [] | ||
// Object.keys(config.headers).filter(h=>config.headers[h].not_blank===true).forEach(h=> { | ||
// if (!(h in row.data) || row.data[h]==='') { | ||
// lineErrors.push(DataError('Error', 'BlankValue', `"${h}" cannot be blank`, line_number)) | ||
// } | ||
// }) | ||
// return lineErrors | ||
// } | ||
// function checkTypes(row) { | ||
// let lineErrors = [] | ||
// Object.keys(config.headers).filter(h=>config.headers[h].type!==undefined && config.headers[h].type!=='string' ).forEach(h=> { | ||
// if (h in row.data && row.data[h]!=='') { | ||
// const {isValid, message} = TYPE_VALIDATOR[config.headers[h].type].validate(row.data[h], config.headers[h]) | ||
// if (!isValid) { | ||
// lineErrors.push(DataError('Error', 'TypeMismatch', `"${row.data[h]}" is not a valid ${config.headers[h].type} value for "${h}": ${message}`, line_number)) | ||
// } | ||
// } | ||
// }) | ||
// return lineErrors | ||
// } | ||
// function checkConstraints(row) { | ||
// let lineErrors = [] | ||
// if (config.constraints && Array.isArray(config.constraints)) { | ||
// config.constraints.forEach(c=>{ | ||
// const {isValid, message} = CONSTRAINT_CLASS[c.type].check(row, c) | ||
// if (!isValid) { | ||
// lineErrors.push(DataError('Error', c.type, message, line_number)) | ||
// } | ||
// }) | ||
// } | ||
// return lineErrors | ||
// } | ||
// function checkHeaders(fields) { | ||
// const reject_additional_headers = config.reject_additional_headers === true | ||
// Object.keys(config.headers).filter(h=>config.headers[h].required).forEach(h => { | ||
// if (!fields.includes(h)) { | ||
// addError('Error','MissingHeader',`Missing mandatory column header "${h}"`) | ||
// } | ||
// }) | ||
// if (reject_additional_headers) { | ||
// fields.filter(f=>!(f in config.headers)).forEach(f=>{ | ||
// addError('Error', 'InvalidHeader', `"${f}" is not a valid header`) | ||
// }) | ||
// } | ||
// } | ||
// let meta | ||
// // Parse local CSV file | ||
// await new Promise(resolve => Papa.parse(content, { | ||
// worker: true, | ||
// delimiter: ',', | ||
// header: true, | ||
// skipEmptyLines: false, | ||
// step: function(row) { | ||
// if (row.meta) meta=row.meta | ||
// line_number++ | ||
// if (_isNotEmptyRow(row)) { | ||
// const lineErrors = row.errors.length ? row.errors : checkForRowErrors(row) | ||
// if (lineErrors.length) { | ||
// lineErrors.forEach(e => rowStatus[e.row] = false) | ||
// addErrors(lineErrors) | ||
// } else { | ||
// rowStatus[line_number] = true | ||
// } | ||
// } else { | ||
// emptyRowCount++ | ||
// if (row.errors.length) { | ||
// addErrors(row.errors) | ||
// } else { | ||
// addError('Warning', 'EmptyValues', 'Line contains no values', line_number) | ||
// } | ||
// } | ||
// }, | ||
// complete: function() { | ||
// resolve() | ||
// } | ||
// })) | ||
// checkHeaders(meta.fields) | ||
// const validRowCount = Object.values(rowStatus).filter(Boolean).length | ||
// let invalidRowCount = Object.keys(rowStatus).length - validRowCount | ||
// Object.assign(meta, {validRowCount, emptyRowCount, invalidRowCount}) | ||
// return { | ||
// errors, | ||
// meta | ||
// } | ||
// } | ||
function buildIndexes(config) { | ||
const indexes = [] | ||
if (config.headers) { | ||
Object.keys(config.headers).forEach(headerName=>{ | ||
config.headers[headerName] = config.headers[headerName] || {} | ||
const headerConf = config.headers[headerName] | ||
if (headerConf.unique) { | ||
indexes.push(UniqueIndex(headerName)) | ||
} | ||
}) | ||
} | ||
return indexes | ||
} | ||
// function _isEmpty(val) { | ||
// return val==='' | ||
// } | ||
// function _isNotEmptyRow(row) { | ||
// return row.data && Object.keys(row.data).length>0 && !Object.values(row.data).every(_isEmpty) | ||
// } | ||
function DataError(type, code, message, row) { | ||
return {type, code, message, row} | ||
} | ||
// function buildIndexes(config) { | ||
// const indexes = [] | ||
// if (config.headers) { | ||
// Object.keys(config.headers).forEach(headerName=>{ | ||
// config.headers[headerName] = config.headers[headerName] || {} | ||
// const headerConf = config.headers[headerName] | ||
// if (headerConf.unique) { | ||
// indexes.push(UniqueIndex(headerName)) | ||
// } | ||
// }) | ||
// } | ||
// return indexes | ||
// } | ||
function UniqueIndex(headerName) { | ||
function unicityError(headerName, value, row) { | ||
return DataError('Error', 'ValueNotUnique', `${headerName} "${value}" is not unique`, row) | ||
} | ||
store = {} | ||
return { | ||
headerName, | ||
/** Adds a value to the index and returns a list of unicityError in case of duplicate values (one for each row with duplicate value) */ | ||
addValue(value, row) { | ||
if (value!==undefined && value!==null && value!=='') { | ||
if (value in store) { | ||
store[value].push(row) | ||
const errors = [unicityError(headerName, value, row)] | ||
if (store[value].length===2) { | ||
errors.push(unicityError(headerName, value, store[value][0])) | ||
} | ||
return errors | ||
} else { | ||
store[value] = [row] | ||
} | ||
} | ||
return [] | ||
} | ||
} | ||
} | ||
// function DataError(type, code, message, row) { | ||
// return {type, code, message, row} | ||
// } | ||
// function UniqueIndex(headerName) { | ||
// function unicityError(headerName, value, row) { | ||
// return DataError('Error', 'ValueNotUnique', `${headerName} "${value}" is not unique`, row) | ||
// } | ||
// store = {} | ||
// return { | ||
// headerName, | ||
// /** Adds a value to the index and returns a list of unicityError in case of duplicate values (one for each row with duplicate value) */ | ||
// addValue(value, row) { | ||
// if (value!==undefined && value!==null && value!=='') { | ||
// if (value in store) { | ||
// store[value].push(row) | ||
// const errors = [unicityError(headerName, value, row)] | ||
// if (store[value].length===2) { | ||
// errors.push(unicityError(headerName, value, store[value][0])) | ||
// } | ||
// return errors | ||
// } else { | ||
// store[value] = [row] | ||
// } | ||
// } | ||
// return [] | ||
// } | ||
// } | ||
// } | ||
module.exports = CSVFileValidator |
105962
618
9