diff --git a/lib/core/escape-delimiters.js b/lib/core/escape-delimiters.js index 199d635..731d9ba 100644 --- a/lib/core/escape-delimiters.js +++ b/lib/core/escape-delimiters.js @@ -23,12 +23,19 @@ module.exports = function escapedDelimiters(textDelimiter, rowDelimiter) { let textDelimiterRegex = new RegExp("\\" + textDelimiter, 'g'); let escapedDelimiter = textDelimiter + textDelimiter; + const enclosingCondition = (textDelimiter === '"') ? + (value) => (value.indexOf(rowDelimiter) >= 0 || + value.indexOf(endOfLine) >= 0 || + value.indexOf('"') >= 0) + : (value) => (value.indexOf(rowDelimiter) >= 0 || + value.indexOf(endOfLine) >= 0); + return function(value) { if (!value.replace) return value; // Escape the textDelimiters contained in the field var newValue = value.replace(textDelimiterRegex, escapedDelimiter); - // Escape the whole field if it contains a rowDelimiter or a linebreak - if (newValue.indexOf(rowDelimiter) >= 0 || newValue.indexOf(endOfLine) >= 0) { + // Escape the whole field if it contains a rowDelimiter or a linebreak or double quote + if (enclosingCondition(value)) { newValue = textDelimiter + newValue + textDelimiter; } diff --git a/tests/array.js b/tests/array.js index 81ff8d1..902ab74 100644 --- a/tests/array.js +++ b/tests/array.js @@ -17,7 +17,7 @@ describe('Array', () => { lastname: 'David', escaped: 'I am a "quoted" field' }], {}, (err, csv) => { - expect(csv).to.equal(`name,lastname,escaped${os.EOL}Bob,Smith${os.EOL}James,David,I am a ""quoted"" field`); + expect(csv).to.equal(`name,lastname,escaped${os.EOL}Bob,Smith${os.EOL}James,David,"I am a ""quoted"" field"`); }); }); it('complex', () => { diff --git a/tests/escape-delimiters.js b/tests/escape-delimiters.js index d9504b5..28fc3f0 100644 --- a/tests/escape-delimiters.js +++ b/tests/escape-delimiters.js @@ -12,12 +12,18 @@ describe('escapeDelimiters', () => { const mocks = { simpleText: 'I am a "quoted" field', simpleRow: 'I am a \n multi line field', - complexField: 'I am a \n multi line field containing "textDelimiters"' + complexField: 'I am a \n multi line field containing "textDelimiters"', + alreadyEscaped: '"I contain "double quotes" everywhere !"' }; it('should escape textDelimiters', () => { expect(escapeDelimiters(mocks.simpleText)).to.be.a.string; - expect(escapeDelimiters(mocks.simpleText)).to.be.equal('I am a ""quoted"" field'); + expect(escapeDelimiters(mocks.simpleText)).to.be.equal('"I am a ""quoted"" field"'); + }); + + it('should escape all textDelimiters', () => { + expect(escapeDelimiters(mocks.alreadyEscaped)).to.be.a.string; + expect(escapeDelimiters(mocks.alreadyEscaped)).to.be.equal('"""I contain ""double quotes"" everywhere !"""'); }); it('should escape rowDelimiters', () => { diff --git a/tests/object.js b/tests/object.js index b8a1096..4dad149 100644 --- a/tests/object.js +++ b/tests/object.js @@ -29,7 +29,7 @@ describe('Object', () => { size: [10, 20], escaped: 'I am a "quoted" field' }, {}, (err, csv) => { - expect(csv).to.equal(`cars,12${os.EOL}roads,5${os.EOL}traffic,slow${os.EOL}speed.max,123${os.EOL}speed.avg,20${os.EOL}speed.min,5${os.EOL}size,10;20${os.EOL}escaped,I am a ""quoted"" field`); + expect(csv).to.equal(`cars,12${os.EOL}roads,5${os.EOL}traffic,slow${os.EOL}speed.max,123${os.EOL}speed.avg,20${os.EOL}speed.min,5${os.EOL}size,10;20${os.EOL}escaped,"I am a ""quoted"" field"`); }); }); }); diff --git a/tests/stream.js b/tests/stream.js index cbb20c4..131b3dd 100644 --- a/tests/stream.js +++ b/tests/stream.js @@ -25,7 +25,7 @@ describe('Stream', () => { it('simple', (done) => { var read = new stream.Readable(); var write = getWriteStream((csv) => { - expect(csv).to.equal(`name,lastname,escaped${os.EOL}Bob,Smith${os.EOL}James,David,I am a ""quoted"" field`); + expect(csv).to.equal(`name,lastname,escaped${os.EOL}Bob,Smith${os.EOL}James,David,"I am a ""quoted"" field"`); done(); }); @@ -44,7 +44,7 @@ describe('Stream', () => { it('simple with options', (done) => { var read = new stream.Readable(); var write = getWriteStream((csv) => { - expect(csv).to.equal(`name|lastname|escaped${os.EOL}Bob|Smith${os.EOL}James|David|I am a ""quoted"" field`); + expect(csv).to.equal(`name|lastname|escaped${os.EOL}Bob|Smith${os.EOL}James|David|"I am a ""quoted"" field"`); done(); });