Skip to content

Commit 5fe3296

Browse files
authored
Disable Field count validation of CSV viewer (#35228)
Default behaviour rejected all rows (Records) with more or fewer columns (Fields) than the first row, preventing them from parsing at all and silently hiding them. While RFC4180 section 2.4 says each line _should_ contain the same number of fields, enforcing this on the viewer is unhelpful. This pull request disables that validation, allowing the viewer to render lines with fewer columns than the maximum number within the file. As it's a simple HTML table, this works without additional changes (i.e. no need to manually determine the maximum number of columns), but the default appearance of rows with fewer columns may be undesirable to some people, especially when using CSS that has `td {border-right: none}`. <img width="1408" height="156" alt="Screenshot without cell right borders" src="https://github.com/user-attachments/assets/d4c19bbc-3fd2-4fd1-83a6-1125e953e95b" /> <img width="1397" height="158" alt="Screenshot with cell right borders" src="https://github.com/user-attachments/assets/86aaafcb-d7e8-4228-99a8-7527c823a07c" /> Fixes #16559, #30358. Unfortunately, retaining empty lines is less trivial, so the line numbers on the leftmost column will still not match the source file whenever those are present, though a future PR could address that.
1 parent 3e3c36b commit 5fe3296

File tree

2 files changed

+20
-15
lines changed

2 files changed

+20
-15
lines changed

modules/csv/csv.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ func CreateReader(input io.Reader, delimiter rune) *stdcsv.Reader {
3030
// thus would change `\t\t` to just `\t` or ` ` (two spaces) to just ` ` (single space)
3131
rd.TrimLeadingSpace = true
3232
}
33+
// Don't force validation of every row to have the same number of entries as the first row.
34+
rd.FieldsPerRecord = -1
3335
return rd
3436
}
3537

modules/csv/csv_test.go

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,24 @@ j, ,\x20
9494
},
9595
expectedDelimiter: ',',
9696
},
97+
// case 3 - every delimiter used, default to comma and handle differing number of fields per record
98+
{
99+
csv: `col1,col2
100+
a;b
101+
c@e
102+
f g
103+
h|i
104+
jkl`,
105+
expectedRows: [][]string{
106+
{"col1", "col2"},
107+
{"a;b"},
108+
{"c@e"},
109+
{"f g"},
110+
{"h|i"},
111+
{"jkl"},
112+
},
113+
expectedDelimiter: ',',
114+
},
97115
}
98116

99117
for n, c := range cases {
@@ -119,21 +137,6 @@ func TestDetermineDelimiterShortBufferError(t *testing.T) {
119137
assert.Nil(t, rd, "CSV reader should be mnil")
120138
}
121139

122-
func TestDetermineDelimiterReadAllError(t *testing.T) {
123-
rd, err := CreateReaderAndDetermineDelimiter(nil, strings.NewReader(`col1,col2
124-
a;b
125-
c@e
126-
f g
127-
h|i
128-
jkl`))
129-
assert.NoError(t, err, "CreateReaderAndDetermineDelimiter() shouldn't throw error")
130-
assert.NotNil(t, rd, "CSV reader should not be mnil")
131-
rows, err := rd.ReadAll()
132-
assert.Error(t, err, "RaadAll() should throw error")
133-
assert.ErrorIs(t, err, csv.ErrFieldCount)
134-
assert.Empty(t, rows, "rows should be empty")
135-
}
136-
137140
func TestDetermineDelimiter(t *testing.T) {
138141
cases := []struct {
139142
csv string

0 commit comments

Comments
 (0)