[Bug] Fix the CSV parser blanking a table (#9919)

* Fix the CSV parser blanking a table

getCellInfo read the loop variable i before its declaration, so hoisting made
it undefined and charAt(undefined) read the first character of the whole text.
Any CSV opening with a separator therefore returned every cell empty.

- Test the cell against the start of the cell rather than the hoisted i
- Keep a separator inside a quoted cell literal
- Cover the parser with tests

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Add a change note for the CSV fix

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joshua Fontany
2026-07-14 17:26:59 +02:00
committed by GitHub
co-authored by Claude Opus 4.8
parent 04cd3081e4
commit 4bf7e9d192
3 changed files with 56 additions and 1 deletions
+2 -1
View File
@@ -15,7 +15,8 @@ var getCellInfo = function(text, start, length, SEPARATOR) {
var isCellQuoted = text.charAt(start) === QUOTE;
var cellStart = isCellQuoted ? start + 1 : start;
if(text.charAt(i) === SEPARATOR) {
// A quote licenses a separator inside the cell, so only an unquoted cell reads an immediate separator as empty
if(!isCellQuoted && text.charAt(cellStart) === SEPARATOR) {
return [cellStart, cellStart, false];
}
+41
View File
@@ -0,0 +1,41 @@
/*\
title: test-csv.js
type: application/javascript
tags: [[$:/tags/test-spec]]
Tests the CSV parser.
\*/
"use strict";
describe("CSV tests", function() {
it("parses a simple table", function() {
expect($tw.utils.parseCsvString("a,b,c\n1,2,3")).toEqual([["a","b","c"],["1","2","3"]]);
});
it("parses a table whose first cell reads empty", function() {
expect($tw.utils.parseCsvString(",b,c\n1,2,3")).toEqual([["","b","c"],["1","2","3"]]);
});
it("parses an empty cell in the middle of a row", function() {
expect($tw.utils.parseCsvString("a,,c")).toEqual([["a","","c"]]);
});
it("parses quoted cells", function() {
expect($tw.utils.parseCsvString('a,"b,still b",c')).toEqual([["a","b,still b","c"]]);
});
it("parses a quoted cell holding an escaped quote", function() {
expect($tw.utils.parseCsvString('a,"b ""quoted""",c')).toEqual([["a",'b "quoted"',"c"]]);
});
it("honours a custom separator", function() {
expect($tw.utils.parseCsvString("a;b;c",{separator: ";"})).toEqual([["a","b","c"]]);
});
it("parses a table with a header row into hashmaps", function() {
expect($tw.utils.parseCsvStringWithHeader("a,b\n1,2")).toEqual([{a: "1", b: "2"}]);
});
});
@@ -0,0 +1,13 @@
title: $:/changenotes/5.5.0/#9919
created: 20260712000000000
modified: 20260712000000000
description: Fix the CSV parser returning every cell empty
release: 5.5.0
tags: $:/tags/ChangeNote
change-type: bugfix
change-category: internal
github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9919
github-contributors: joshuafontany
type: text/vnd.tiddlywiki
`getCellInfo` read its loop variable before the loop declared it, so hoisting made it undefined and the parser tested the first character of the whole text rather than the first character of the cell. Any CSV opening with a separator therefore returned every cell empty, and the table rendered blank.