Skip to content

Commit ab3bf8a

Browse files
authored
fix: Escape quotes excel (#512)
* fix: properly escape quotes when using excel mode * refactor: fix typo in comments * perf: do quote replacement in a single pass
1 parent e1ba2c1 commit ab3bf8a

File tree

6 files changed

+76
-11
lines changed

6 files changed

+76
-11
lines changed

lib/JSON2CSVBase.js

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -168,14 +168,16 @@ class JSON2CSVBase {
168168
}
169169

170170
if (typeof value === 'string') {
171-
if(value.includes(this.opts.quote)) {
172-
value = value.replace(new RegExp(this.opts.quote, 'g'), this.opts.escapedQuote);
173-
}
174-
175-
value = `${this.opts.quote}${value}${this.opts.quote}`;
176-
177171
if (this.opts.excelStrings) {
178-
value = `"="${value}""`;
172+
if(value.includes(this.opts.quote)) {
173+
value = value.replace(new RegExp(this.opts.quote, 'g'), `${this.opts.escapedQuote}${this.opts.escapedQuote}`);
174+
}
175+
value = `"=""${value}"""`;
176+
} else {
177+
if(value.includes(this.opts.quote)) {
178+
value = value.replace(new RegExp(this.opts.quote, 'g'), this.opts.escapedQuote);
179+
}
180+
value = `${this.opts.quote}${value}${this.opts.quote}`;
179181
}
180182
}
181183

test/CLI.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ module.exports = (testRunner, jsonFixtures, csvFixtures) => {
430430
});
431431
});
432432

433-
// Excell
433+
// Excel
434434

435435
testRunner.add('should format strings to force excel to view the values as strings', (t) => {
436436
const opts = '--fields carModel,price,color --excel-strings';
@@ -443,6 +443,17 @@ module.exports = (testRunner, jsonFixtures, csvFixtures) => {
443443
});
444444
});
445445

446+
testRunner.add('should format strings to force excel to view the values as strings with escaped quotes', (t) => {
447+
const opts = '--excel-strings';
448+
449+
exec(`${cli} -i "${getFixturePath('/json/quotes.json')}" ${opts}`, (err, stdout, stderr) => {
450+
t.notOk(stderr);
451+
const csv = stdout;
452+
t.equal(csv, csvFixtures.excelStringsWithEscapedQuoted);
453+
t.end();
454+
});
455+
});
456+
446457
// Escaping and preserving values
447458

448459
testRunner.add('should parse JSON values with trailing backslashes', (t) => {

test/JSON2CSVAsyncParser.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -768,7 +768,7 @@ module.exports = (testRunner, jsonFixtures, csvFixtures, inMemoryJsonFixtures) =
768768
t.end();
769769
});
770770

771-
// Excell
771+
// Excel
772772

773773
testRunner.add('should format strings to force excel to view the values as strings', async (t) => {
774774
const opts = {
@@ -787,6 +787,22 @@ module.exports = (testRunner, jsonFixtures, csvFixtures, inMemoryJsonFixtures) =
787787
t.end();
788788
});
789789

790+
testRunner.add('should format strings to force excel to view the values as strings with escaped quotes', async (t) => {
791+
const opts = {
792+
excelStrings:true
793+
};
794+
const parser = new AsyncParser(opts);
795+
796+
try {
797+
const csv = await parser.fromInput(jsonFixtures.quotes()).promise();
798+
t.equal(csv, csvFixtures.excelStringsWithEscapedQuoted);
799+
} catch(err) {
800+
t.fail(err.message);
801+
}
802+
803+
t.end();
804+
});
805+
790806
// Escaping and preserving values
791807

792808
testRunner.add('should parse JSON values with trailing backslashes', async (t) => {

test/JSON2CSVParser.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,7 @@ module.exports = (testRunner, jsonFixtures, csvFixtures) => {
515515
t.end();
516516
});
517517

518-
// Excell
518+
// Excel
519519

520520
testRunner.add('should format strings to force excel to view the values as strings', (t) => {
521521
const opts = {
@@ -530,6 +530,18 @@ module.exports = (testRunner, jsonFixtures, csvFixtures) => {
530530
t.end();
531531
});
532532

533+
testRunner.add('should format strings to force excel to view the values as strings with escaped quotes', (t) => {
534+
const opts = {
535+
excelStrings:true
536+
};
537+
538+
const parser = new Json2csvParser(opts);
539+
const csv = parser.parse(jsonFixtures.quotes);
540+
541+
t.equal(csv, csvFixtures.excelStringsWithEscapedQuoted);
542+
t.end();
543+
});
544+
533545
// Escaping and preserving values
534546

535547
testRunner.add('should parse JSON values with trailing backslashes', (t) => {

test/JSON2CSVTransform.js

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -842,7 +842,7 @@ module.exports = (testRunner, jsonFixtures, csvFixtures, inMemoryJsonFixtures) =
842842
});
843843
});
844844

845-
// Excell
845+
// Excel
846846

847847
testRunner.add('should format strings to force excel to view the values as strings', (t) => {
848848
const opts = {
@@ -866,6 +866,27 @@ module.exports = (testRunner, jsonFixtures, csvFixtures, inMemoryJsonFixtures) =
866866
});
867867
});
868868

869+
testRunner.add('should format strings to force excel to view the values as strings with escaped quotes', (t) => {
870+
const opts = {
871+
excelStrings:true
872+
};
873+
874+
const transform = new Json2csvTransform(opts);
875+
const processor = jsonFixtures.quotes().pipe(transform);
876+
877+
let csv = '';
878+
processor
879+
.on('data', chunk => (csv += chunk.toString()))
880+
.on('end', () => {
881+
t.equal(csv, csvFixtures.excelStringsWithEscapedQuoted);
882+
t.end();
883+
})
884+
.on('error', err => {
885+
t.fail(err.message);
886+
t.end();
887+
});
888+
});
889+
869890
// Escaping and preserving values
870891

871892
testRunner.add('should parse JSON values with trailing backslashes', (t) => {
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
"=""a string"""
2+
"=""with a description"""
3+
"=""with a description and """"quotes"""""""

0 commit comments

Comments
 (0)