Most appropriate sub-area of p5.js?
p5.js version
2.3.4 (also on main)
Web browser and version
Chrome 153
Operating system
Linux
Steps to reproduce this
loadTable() drops the last row of a one-column CSV that doesn't end with a newline. If the file is a single value, it throws instead.
With names.csv containing alice\nbob\ncarol (no newline at the end):
async function setup() {
noCanvas();
const t = await loadTable('names.csv');
print(t.getRowCount()); // 2, expected 3
print(t.getArray()); // [["alice"], ["bob"]]
}
alice\nbob\ncarol\n (with a trailing newline) gives 3 rows, as expected.
- A file containing just
42 throws Cannot read properties of undefined (reading 'length'). FES then reports "there was a problem loading your table file. Try checking if the file path is correct", which sends people looking at the wrong thing.
- Multi-column files aren't affected:
x,y\n1,2 parses fine without a trailing newline.
The cause is in src/io/csv.js, at the end of parse():
// flush the last value
if (ctx.entry.length !== 0) {
valueEnd(ctx);
entryEnd(ctx);
}
ctx.entry only gets a value when a separator or newline ends it. In a one-column row, the last value is still sitting in ctx.value with ctx.entry empty, so the flush is skipped. parse('a\nb') returns [["a"]], parse('only') and parse('"only"') return [], and parse('a\n\nb') loses the b. For the single-value file, loadTable then does data[0].length on an empty array.
I think the fix is to flush whenever the parser is partway through a value, i.e. if (state !== 0 || ctx.entry.length !== 0). State 2 covers an unquoted value and 4 covers a closed quote. A trailing newline leaves state 0 with an empty entry, so it still doesn't add a phantom row. A separate guard in loadTable for an empty file (data[0] undefined) would make that case return an empty table instead of throwing. I'm happy to open a PR with both and unit tests for parse if this sounds right.
Most appropriate sub-area of p5.js?
p5.js version
2.3.4 (also on
main)Web browser and version
Chrome 153
Operating system
Linux
Steps to reproduce this
loadTable()drops the last row of a one-column CSV that doesn't end with a newline. If the file is a single value, it throws instead.With
names.csvcontainingalice\nbob\ncarol(no newline at the end):alice\nbob\ncarol\n(with a trailing newline) gives 3 rows, as expected.42throwsCannot read properties of undefined (reading 'length'). FES then reports "there was a problem loading your table file. Try checking if the file path is correct", which sends people looking at the wrong thing.x,y\n1,2parses fine without a trailing newline.The cause is in
src/io/csv.js, at the end ofparse():ctx.entryonly gets a value when a separator or newline ends it. In a one-column row, the last value is still sitting inctx.valuewithctx.entryempty, so the flush is skipped.parse('a\nb')returns[["a"]],parse('only')andparse('"only"')return[], andparse('a\n\nb')loses theb. For the single-value file,loadTablethen doesdata[0].lengthon an empty array.I think the fix is to flush whenever the parser is partway through a value, i.e.
if (state !== 0 || ctx.entry.length !== 0). State2covers an unquoted value and4covers a closed quote. A trailing newline leaves state0with an empty entry, so it still doesn't add a phantom row. A separate guard inloadTablefor an empty file (data[0]undefined) would make that case return an empty table instead of throwing. I'm happy to open a PR with both and unit tests forparseif this sounds right.