Skip to content

Commit

Permalink
fix: simplify stringExcel formatter and support proper escaping (#513)
Browse files Browse the repository at this point in the history
  • Loading branch information
juanjoDiaz authored Jan 28, 2021
1 parent 5c62da1 commit 50062c3
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 21 deletions.
12 changes: 3 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -363,17 +363,11 @@ The formatter needs to be instantiated and takes an options object as arguments
Converts string data into normalized Excel style data after formatting it using the given string formatter.
The formatter needs to be instantiated and takes an options object as arguments containing:
- `stringFormatter` - Boolean, whether to flatten JSON objects or not. Defaults to our built-in `stringFormatter`.
The formatter needs to be instantiated and takes no arguments.
```js
{
// Uses the default string formatter
string: stringExcelFormatter(),
// Uses custom string formatter
string: stringExcelFormatter(myStringFormatter()),
string: stringExcelFormatter,
}
```
Expand Down Expand Up @@ -614,7 +608,7 @@ should be replaced by
const { Parser, formatter: { stringExcel: stringExcelFormatter } } = require('json2csv');
const json2csvParser = new Parser({
formatters: {
string: stringExcelFormatter(stringFormatter({ quote: '\'', escapedQuote: '\\\'' }))),
string: stringExcelFormatter,
}
});
const csv = json2csvParser.parse(myData);
Expand Down
13 changes: 7 additions & 6 deletions bin/json2csv.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const readFile = promisify(readFileOrig);
const writeFile = promisify(writeFileOrig);

const { unwind, flatten } = json2csv.transforms;
const { string: stringFormatterCtr, stringExcel: stringExcelFormatter } = json2csv.formatters;
const { string: stringFormatter, stringExcel: stringExcelFormatter } = json2csv.formatters;
const JSON2CSVParser = json2csv.Parser;
const Json2csvTransform = json2csv.Transform;

Expand Down Expand Up @@ -151,12 +151,13 @@ async function processStream(config, opts) {
}));
}

const stringFormatter = stringFormatterCtr({
quote: config.quote,
escapedQuote: config.escapedQuote,
});
const formatters = {
string: config.excelStrings ? stringExcelFormatter({ stringFormatter }) : stringFormatter
string: config.excelStrings
? stringExcelFormatter
: stringFormatter({
quote: config.quote,
escapedQuote: config.escapedQuote,
})
};

const opts = {
Expand Down
7 changes: 4 additions & 3 deletions lib/formatters/stringExcel.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
const defaulStringFormatter = require('./string');
const quote = '"';
const escapedQuote = '""""';

function stringExcel(opts = { stringFormatter: defaulStringFormatter() }) {
return (value) => `"="${opts.stringFormatter(value)}""`;
function stringExcel(value) {
return `"=""${value.replace(new RegExp(quote, 'g'), escapedQuote)}"""`;
}

module.exports = stringExcel;
11 changes: 11 additions & 0 deletions test/CLI.js
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,17 @@ module.exports = (testRunner, jsonFixtures, csvFixtures) => {
});
});

testRunner.add('should format strings to force excel to view the values as strings with escaped quotes', (t) => {
const opts = '--excel-strings';

exec(`${cli} -i "${getFixturePath('/json/quotes.json')}" ${opts}`, (err, stdout, stderr) => {
t.notOk(stderr);
const csv = stdout;
t.equal(csv, csvFixtures.excelStringsWithEscapedQuoted);
t.end();
});
});

// String Escaping and preserving values

testRunner.add('should parse JSON values with trailing backslashes', (t) => {
Expand Down
21 changes: 20 additions & 1 deletion test/JSON2CSVAsyncParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -1202,7 +1202,7 @@ module.exports = (testRunner, jsonFixtures, csvFixtures, inMemoryJsonFixtures) =
const opts = {
fields: ['carModel', 'price', 'color'],
formatters: {
string: stringExcelFormatter()
string: stringExcelFormatter
}
};
const parser = new AsyncParser(opts);
Expand All @@ -1217,6 +1217,25 @@ module.exports = (testRunner, jsonFixtures, csvFixtures, inMemoryJsonFixtures) =
t.end();
});

testRunner.add('should format strings to force excel to view the values as strings with escaped quotes', async (t) => {
const opts = {
formatters: {
string: stringExcelFormatter
}
};
const parser = new AsyncParser(opts);

try {
const csv = await parser.parse(jsonFixtures.quotes()).promise();
t.equal(csv, csvFixtures.excelStringsWithEscapedQuoted);
} catch(err) {
t.fail(err.message);
}

t.end();
});


// String Escaping and preserving values

testRunner.add('should parse JSON values with trailing backslashes', async (t) => {
Expand Down
16 changes: 15 additions & 1 deletion test/JSON2CSVParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -875,7 +875,7 @@ module.exports = (testRunner, jsonFixtures, csvFixtures) => {
const opts = {
fields: ['carModel', 'price', 'color'],
formatters: {
string: stringExcelFormatter()
string: stringExcelFormatter
}
};

Expand All @@ -886,6 +886,20 @@ module.exports = (testRunner, jsonFixtures, csvFixtures) => {
t.end();
});

testRunner.add('should format strings to force excel to view the values as strings with escaped quotes', (t) => {
const opts = {
formatters: {
string: stringExcelFormatter
}
};

const parser = new Json2csvParser(opts);
const csv = parser.parse(jsonFixtures.quotes);

t.equal(csv, csvFixtures.excelStringsWithEscapedQuoted);
t.end();
});

// String Escaping and preserving values

testRunner.add('should parse JSON values with trailing backslashes', (t) => {
Expand Down
26 changes: 25 additions & 1 deletion test/JSON2CSVTransform.js
Original file line number Diff line number Diff line change
Expand Up @@ -1381,7 +1381,7 @@ module.exports = (testRunner, jsonFixtures, csvFixtures, inMemoryJsonFixtures) =
const opts = {
fields: ['carModel', 'price', 'color'],
formatters: {
string: stringExcelFormatter()
string: stringExcelFormatter
}
};

Expand All @@ -1401,6 +1401,30 @@ module.exports = (testRunner, jsonFixtures, csvFixtures, inMemoryJsonFixtures) =
});
});

testRunner.add('should format strings to force excel to view the values as strings with escaped quotes', (t) => {
const opts = {
formatters: {
string: stringExcelFormatter
}
};

const transform = new Json2csvTransform(opts);
const processor = jsonFixtures.quotes().pipe(transform);

let csv = '';
processor
.on('data', chunk => (csv += chunk.toString()))
.on('end', () => {
t.equal(csv, csvFixtures.excelStringsWithEscapedQuoted);
t.end();
})
.on('error', err => {
t.fail(err.message);
t.end();
});
});


// String Escaping and preserving values

testRunner.add('should parse JSON values with trailing backslashes', (t) => {
Expand Down
3 changes: 3 additions & 0 deletions test/fixtures/csv/excelStringsWithEscapedQuoted.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"=""a string"""
"=""with a description"""
"=""with a description and """"quotes"""""""

0 comments on commit 50062c3

Please sign in to comment.