From 3a79dbc9988b286a67a13c75ab2e3ab6f2c3c30b Mon Sep 17 00:00:00 2001 From: Avinash Kumar Deepak Date: Thu, 12 Mar 2026 22:19:37 +0530 Subject: [PATCH] Fix saveTable() not escaping double quotes in CSV output --- src/io/files.js | 31 +++++++++++++++---------------- test/unit/io/saveTable.js | 12 ++++++------ 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/io/files.js b/src/io/files.js index 88d627b25a..5598dd42d5 100644 --- a/src/io/files.js +++ b/src/io/files.js @@ -2272,6 +2272,16 @@ function escapeHelper(content) { .replace(/'/g, '''); } +// RFC 4180 escape: double inner quotes, wrap when value has comma/quote/newline +function csvEscape(val, ext) { + if (ext !== 'csv') return String(val); + let s = String(val); + if (s.includes(',') || s.includes('"') || s.includes('\n')) { + return '"' + s.replace(/"/g, '""') + '"'; + } + return s; +} + /** * Writes the contents of a Table object to a file. Defaults to a * text file with comma-separated-values ('csv') but can also @@ -2331,9 +2341,9 @@ p5.prototype.saveTable = function(table, filename, options) { if (header[0] !== '0') { for (let h = 0; h < header.length; h++) { if (h < header.length - 1) { - pWriter.write(header[h] + sep); + pWriter.write(csvEscape(header[h], ext) + sep); } else { - pWriter.write(header[h]); + pWriter.write(csvEscape(header[h], ext)); } } pWriter.write('\n'); @@ -2341,22 +2351,11 @@ p5.prototype.saveTable = function(table, filename, options) { // make rows for (let i = 0; i < table.rows.length; i++) { - let j; - for (j = 0; j < table.rows[i].arr.length; j++) { + for (let j = 0; j < table.rows[i].arr.length; j++) { if (j < table.rows[i].arr.length - 1) { - //double quotes should be inserted in csv only if contains comma separated single value - if (ext === 'csv' && String(table.rows[i].arr[j]).includes(',')) { - pWriter.write('"' + table.rows[i].arr[j] + '"' + sep); - } else { - pWriter.write(table.rows[i].arr[j] + sep); - } + pWriter.write(csvEscape(table.rows[i].arr[j], ext) + sep); } else { - //double quotes should be inserted in csv only if contains comma separated single value - if (ext === 'csv' && String(table.rows[i].arr[j]).includes(',')) { - pWriter.write('"' + table.rows[i].arr[j] + '"'); - } else { - pWriter.write(table.rows[i].arr[j]); - } + pWriter.write(csvEscape(table.rows[i].arr[j], ext)); } } pWriter.write('\n'); diff --git a/test/unit/io/saveTable.js b/test/unit/io/saveTable.js index 52b0c58980..ad9e6ccb4e 100644 --- a/test/unit/io/saveTable.js +++ b/test/unit/io/saveTable.js @@ -86,12 +86,12 @@ suite('saveTable', function() { myp5.saveTable(myTable, 'filename'); let myBlob = blobContainer.blob; let text = await myBlob.text(); - let myTableStr = myTable.columns.join(',') + '\n'; - for (let i = 0; i < myTable.rows.length; i++) { - myTableStr += myTable.rows[i].arr.join(',') + '\n'; - } - - assert.strictEqual(text, myTableStr); + let expected = + 'name,age,height\n' + + 'David,31,80\n' + + '"David, Jr.",11,61.5\n' + + '"David,\nSr. ""the boss""",95,88\n'; + assert.strictEqual(text, expected); }, true );