Skip to content

Commit

Permalink
Merge pull request #102 from shystruk/dev
Browse files Browse the repository at this point in the history
Upgrade papaparse. Return rowIndex and columnIndex with a message
  • Loading branch information
shystruk authored Jul 27, 2022
2 parents cdf1915 + a4a60fc commit 37acef6
Show file tree
Hide file tree
Showing 15 changed files with 1,669 additions and 721 deletions.
106 changes: 73 additions & 33 deletions demo-ts/dist/bundle.js

Large diffs are not rendered by default.

25 changes: 25 additions & 0 deletions demo-ts/dist/csv-file-validator.test-d.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions demo-ts/dist/csv-file-validator.test-d.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions demo-ts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ const CSVConfig: ValidatorConfig = {
document.getElementById('file').onchange = function (event: any) {
CSVFileValidator<CSVRow>(event.target.files[0], CSVConfig)
.then((csvData: ParsedResults) => {
csvData.inValidMessages.forEach((message: string) => {
document.getElementById('invalidMessages').insertAdjacentHTML('beforeend', message)
csvData.inValidData.forEach((item) => {
document.getElementById('invalidMessages').insertAdjacentHTML('beforeend', item.message)
})
console.log(csvData.inValidMessages)
console.log(csvData.inValidData)
console.log(csvData.data)
})
}
2 changes: 1 addition & 1 deletion demo-ts/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"esModuleInterop": true,
"target": "es6",
"noImplicitAny": true,
"moduleResolution": "classic",
"moduleResolution": "node",
"sourceMap": true,
"baseUrl": ".",
"outDir": "dist",
Expand Down
903 changes: 903 additions & 0 deletions demo-ts/yarn.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion demo/dist/bundle.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion demo/dist/bundle.js.LICENSE.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* @license
Papa Parse
v5.3.0
v5.3.2
https://github.com/mholt/PapaParse
License: MIT
*/
2 changes: 1 addition & 1 deletion demo/dist/bundle.js.map

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions demo/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ const CSVConfig = {
document.getElementById('file').onchange = function (event) {
CSVFileValidator(event.target.files[0], CSVConfig)
.then(csvData => {
csvData.inValidMessages.forEach(message => {
document.getElementById('invalidMessages').insertAdjacentHTML('beforeend', message)
csvData.inValidData.forEach(item => {
document.getElementById('invalidMessages').insertAdjacentHTML('beforeend', item.message)
})
console.log(csvData.inValidMessages)
console.log(csvData.inValidData)
console.log(csvData.data)
})
}
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@
"dependencies": {
"famulus": "^2.2.3",
"lodash": "^4.17.21",
"papaparse": "^5.3.1"
"papaparse": "^5.3.2"
},
"devDependencies": {
"@types/papaparse": "^5.2.6",
"@types/papaparse": "^5.3.2",
"ava": "^0.25.0",
"codecov.io": "^0.1.6",
"nyc": "^11.4.1",
Expand Down
14 changes: 10 additions & 4 deletions src/csv-file-validator.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,18 @@ export interface FieldSchema {
columnNumber: number) => string;
}

export interface ParsedResults<Row = any, Error = string> {
export interface RowError {
rowIndex?: number;
columnIndex?: number;
message: string;
}

export interface ParsedResults<Row = any, Error = RowError> {
/** Array of parsed CSV entries */
data: Row[];

/** List of validation error messages */
inValidMessages: Error[];
/** List of validation errors data */
inValidData: Error[];
}

/** CSV File Validator configuration */
Expand All @@ -79,7 +85,7 @@ export interface ValidatorConfig {
parserConfig?: ParseConfig;
}

export default function CSVFileValidator<Row = any, Error = string>(
export default function CSVFileValidator<Row = any, Error = RowError>(
csv: string | File | NodeJS.ReadableStream,
config: ValidatorConfig
): Promise<ParsedResults<Row, Error>>;
50 changes: 33 additions & 17 deletions src/csv-file-validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
return new Promise(function (resolve, reject) {
if (!config || (config && !config.headers)) {
return resolve({
inValidMessages: ['config headers are required'],
inValidData: [{ message: 'config headers are required' }],
data: []
});
}
Expand All @@ -44,7 +44,7 @@
*/
function _prepareDataAndValidateFile(csvData, config) {
const file = {
inValidMessages: [],
inValidData: [],
data: []
};

Expand All @@ -53,9 +53,11 @@

// fields are mismatch
if (rowIndex !== 0 && row.length !== config.headers.length) {
file.inValidMessages.push(
'Number of fields mismatch: expected ' + config.headers.length + ' fields' +
' but parsed ' + row.length + '. In the row ' + rowIndex
file.inValidData.push({
rowIndex,
message: 'Number of fields mismatch: expected ' + config.headers.length + ' fields' +
' but parsed ' + row.length + '. In the row ' + rowIndex
}
);
}

Expand All @@ -76,11 +78,14 @@

if (!config.isHeaderNameOptional) {
if (valueConfig.name !== columnValue) {
file.inValidMessages.push(
_isFunction(valueConfig.headerError)
file.inValidData.push({
rowIndex: rowIndex + 1,
columnIndex: columnIndex + 1,
message: _isFunction(valueConfig.headerError)
? valueConfig.headerError(columnValue, valueConfig.name, rowIndex + 1, columnIndex + 1)
: 'Header name ' + columnValue + ' is not correct or missing in the ' + (rowIndex + 1) + ' row / '
+ (columnIndex + 1) + ' column. The Header name should be ' + valueConfig.name
+ (columnIndex + 1) + ' column. The Header name should be ' + valueConfig.name
}
);
}

Expand All @@ -89,26 +94,35 @@
}

if (valueConfig.required && !columnValue.length) {
file.inValidMessages.push(
_isFunction(valueConfig.requiredError)
file.inValidData.push({
rowIndex: rowIndex + 1,
columnIndex: columnIndex + 1,
message: _isFunction(valueConfig.requiredError)
? valueConfig.requiredError(valueConfig.name, rowIndex + 1, columnIndex + 1)
: String(valueConfig.name + ' is required in the ' + (rowIndex + 1) + ' row / ' + (columnIndex + 1) + ' column')
}
);

} else if (valueConfig.validate && !valueConfig.validate(columnValue)) {
file.inValidMessages.push(
_isFunction(valueConfig.validateError)
file.inValidData.push({
rowIndex: rowIndex + 1,
columnIndex: columnIndex + 1,
message: _isFunction(valueConfig.validateError)
? valueConfig.validateError(valueConfig.name, rowIndex + 1, columnIndex + 1)
: String(valueConfig.name + ' is not valid in the ' + (rowIndex + 1) + ' row / ' + (columnIndex + 1) + ' column')
}
);
} else if (valueConfig.dependentValidate &&
!valueConfig.dependentValidate(columnValue, _getClearRow(row))) {
file.inValidMessages.push(
_isFunction(valueConfig.validateError)
file.inValidData.push({
rowIndex: rowIndex + 1,
columnIndex: columnIndex + 1,
message: _isFunction(valueConfig.validateError)
? valueConfig.validateError(valueConfig.name, rowIndex + 1, columnIndex + 1)
: String(valueConfig.name + ' not passed dependent validation in the ' + (rowIndex + 1) + ' row / ' + (columnIndex + 1) + ' column')
}
);
}

if (valueConfig.optional) {
columnData[valueConfig.inputName] = columnValue;
}
Expand Down Expand Up @@ -152,10 +166,12 @@
const value = row[header.inputName];

if (duplicates.indexOf(value) >= 0) {
file.inValidMessages.push(
_isFunction(header.uniqueError)
file.inValidData.push({
rowIndex: rowIndex + 2,
message: _isFunction(header.uniqueError)
? header.uniqueError(header.name, rowIndex + 2)
: String(`${header.name} is not unique at the ${rowIndex + 2} row`)
}
);
} else {
duplicates.push(value);
Expand Down
26 changes: 14 additions & 12 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,50 +78,50 @@ test('should return the message "config headers are required"', async t => {
const csvData = await CSVFileValidator('');

t.is(typeof csvData, 'object');
t.deepEqual(csvData.inValidMessages, ['config headers are required']);
t.deepEqual(csvData.inValidData, [{ message: 'config headers are required' }]);
t.deepEqual(csvData.data, []);
});

test('should return no data if the file is empty', async t => {
const csvData = await CSVFileValidator('', CSVConfig);

t.is(typeof csvData, 'object');
t.deepEqual(csvData.inValidMessages, []);
t.deepEqual(csvData.inValidData, []);
t.deepEqual(csvData.data, []);
});

test('should return invalid messages with data', async t => {
const csvData = await CSVFileValidator(CSVInvalidFile, CSVConfig);

t.is(csvData.inValidMessages.length, 5);
t.is(csvData.inValidData.length, 5);
t.is(csvData.data.length, 2);
});

test('should return data, the file is valid', async t => {
const csvData = await CSVFileValidator(CSVValidFile, CSVConfig);

t.is(csvData.inValidMessages.length, 2);
t.is(csvData.inValidData.length, 2);
t.is(csvData.data.length, 2);
});

test('file without headers, the file is valid and headers are optional', async t => {
const csvData = await CSVFileValidator(CSVValidFileWithoutHeaders, { ...CSVConfig, isHeaderNameOptional: true });

t.is(csvData.inValidMessages.length, 1);
t.is(csvData.inValidData.length, 1);
t.is(csvData.data.length, 2);
});

test('file with headers, the file is valid and headers are optional', async t => {
const csvData = await CSVFileValidator(CSVValidFile, { ...CSVConfig, isHeaderNameOptional: true });

t.is(csvData.inValidMessages.length, 2);
t.is(csvData.inValidData.length, 2);
t.is(csvData.data.length, 2);
});

test('file is valid and headers are missed', async t => {
const csvData = await CSVFileValidator(CSVValidFileWithoutHeaders, CSVConfig);

t.is(csvData.inValidMessages.length, 6);
t.is(csvData.inValidData.length, 6);
t.is(csvData.data.length, 1);
});

Expand All @@ -134,22 +134,24 @@ test('should return optional column', async t => {
test('file is valid and Email is not unique at the ... row', async t => {
const csvData = await CSVFileValidator(CSVInvalidFileWithDuplicates, CSVConfig);

t.is(csvData.inValidMessages.length, 5);
t.is(csvData.inValidData.length, 5);
t.is(csvData.data.length, 3);
});

test('fields are mismatch: too many fields', async t => {
const csvData = await CSVFileValidator(CSVInvalidFileTooManyFields, { headers: [CSVConfig.headers[0]] });

t.is(csvData.inValidMessages.length, 1);
t.is(csvData.inValidMessages[0], 'Number of fields mismatch: expected 1 fields but parsed 3. In the row 1')
t.is(csvData.inValidData.length, 1);
t.is(csvData.inValidData[0].message, 'Number of fields mismatch: expected 1 fields but parsed 3. In the row 1')
t.is(csvData.inValidData[0].rowIndex, 1)
t.is(csvData.data.length, 1);
});

test('fields are mismatch: not enough fields', async t => {
const csvData = await CSVFileValidator(CSVInvalidFileNotEnoughFields, { headers: [CSVConfig.headers[5], CSVConfig.headers[0], CSVConfig.headers[1]] });

t.is(csvData.inValidMessages.length, 3);
t.is(csvData.inValidMessages[0], 'Number of fields mismatch: expected 3 fields but parsed 2. In the row 1');
t.is(csvData.inValidData.length, 3);
t.is(csvData.inValidData[0].message, 'Number of fields mismatch: expected 3 fields but parsed 2. In the row 1');
t.is(csvData.inValidData[0].rowIndex, 1)
t.is(csvData.data.length, 2);
});
Loading

0 comments on commit 37acef6

Please sign in to comment.