Skip to content

Commit

Permalink
Merge pull request #246 from mrodrig/feat/improved-excludeKeys-matching
Browse files Browse the repository at this point in the history
Feat/improved exclude keys matching
  • Loading branch information
mrodrig authored Feb 21, 2024
2 parents 7b32338 + e18d66c commit 8062ef2
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 2 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ Returns the CSV `string` or rejects with an `Error` if there was an issue.
* `emptyFieldValue` - Any - Value that, if specified, will be substituted in for field values that are `undefined`, `null`, or an empty string.
* Default: none
* `excelBOM` - Boolean - Should a unicode character be prepended to allow Excel to open a UTF-8 encoded file with non-ASCII characters present.
* `excludeKeys` - Array - Specify the keys that should be excluded from the output.
* `excludeKeys` - Array - Specify the keys that should be excluded from the output. Provided keys will also be used as a RegExp to help exclude keys under a specified prefix, such as all keys of Objects in an Array when `expandArrayObjects` is `true`.
* Default: `[]`
* Note: When used with `unwindArrays`, arrays present at excluded key paths will not be unwound.
* `expandNestedObjects` - Boolean - Should nested objects be deep-converted to CSV?
Expand Down
10 changes: 9 additions & 1 deletion src/json2csv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,15 @@ export const Json2Csv = function(options: FullJson2CsvOptions) {
function filterExcludedKeys(keyPaths: string[]) {
if (options.excludeKeys) {
return keyPaths.filter((keyPath) => {
return !options.excludeKeys.includes(keyPath);
for (const excludedKey of options.excludeKeys) {
// Only match if the excludedKey appears at the beginning of the string so we don't accidentally match a key farther down in a key path
const regex = new RegExp(`^${excludedKey}`);

if (excludedKey === keyPath || keyPath.match(regex)) {
return false; // Exclude the key
}
}
return true; // Otherwise, include the key
});
}

Expand Down
1 change: 1 addition & 0 deletions test/config/testCsvFilesList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ const csvFileConfig = [
{key: 'falsyValues', file: '../data/csv/falsyValues.csv'},
{key: 'nestedNotUnwoundObjects', file: '../data/csv/nestedNotUnwoundObjects.csv'},
{key: 'newlineWithWrapDelimiters', file: '../data/csv/newlineWithWrapDelimiters.csv'},
{key: 'excludeKeyPattern', file: '../data/csv/excludeKeyPattern.csv'},
];

function readCsvFile(filePath: string) {
Expand Down
1 change: 1 addition & 0 deletions test/config/testJsonFilesList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,5 @@ export default {
quotedFieldWithNewline: require('../data/json/quotedFieldWithNewline.json'),
falsyValues: require('../data/json/falsyValues.json'),
newlineWithWrapDelimiters: require('../data/json/newlineWithWrapDelimiters'),
excludeKeyPattern: require('../data/json/excludeKeyPattern'),
};
3 changes: 3 additions & 0 deletions test/data/csv/excludeKeyPattern.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
id,name.arr
1,this should appear
2,this should also appear
24 changes: 24 additions & 0 deletions test/data/json/excludeKeyPattern.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[
{
"id": 1,
"arr": [
{
"name": "foo"
}
],
"name": {
"arr": "this should appear"
}
},
{
"id": 2,
"arr": [
{
"name": "bar"
}
],
"name": {
"arr": "this should also appear"
}
}
]
45 changes: 45 additions & 0 deletions test/json2csv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,51 @@ export function runTests() {
assert.equal(csv, updatedCsv);
});

// Test case for #244
it('should exclude a matched key prefix from the output when unwinding arrays', () => {
const updatedCsv = csvTestData.unwind.replace(',data.options.name', '')
.replace(/,MacBook (Pro|Air) \d+/g, '')
.replace(/,(Super|Turbo)charger/g, '')
.replace('5cf7ca3616c91100018844af,Computers\n', '')
// Remove duplicate lines
.replace('5cf7ca3616c91100018844bf,Cars\n', '');

const csv = json2csv(jsonTestData.unwind, {
unwindArrays: true,
expandArrayObjects: true,
excludeKeys: ['data.options']
});

assert.equal(csv, updatedCsv);
});

// Test case for #244
it('should exclude a matched key prefix from the output when unwinding arrays', () => {
const updatedCsv = csvTestData.unwind.replace(',data.category,data.options.name', '')
.replace(/,Computers,MacBook (Pro|Air) \d+/g, '')
.replace(/,Cars,(Super|Turbo)charger/g, '')
.replace('5cf7ca3616c91100018844af\n', '')
// Remove duplicate lines
.replace('5cf7ca3616c91100018844bf\n', '');

const csv = json2csv(jsonTestData.unwind, {
unwindArrays: true,
excludeKeys: ['data']
});

assert.equal(csv, updatedCsv);
});

// Test case for #244
it('should exclude a matched key prefix, but not if it is not at the start of the key path', () => {
const csv = json2csv(jsonTestData.excludeKeyPattern, {
expandArrayObjects: true,
excludeKeys: ['arr']
});

assert.equal(csv, csvTestData.excludeKeyPattern);
});

it('should use a custom value parser function when provided', () => {
const updatedCsv = csvTestData.trimmedFields.split('\n');
const textRow = 'Parsed Value,Parsed Value,Parsed Value,Parsed Value,Parsed Value';
Expand Down

0 comments on commit 8062ef2

Please sign in to comment.