| ... | ... | @@ -21,6 +21,35 @@ describe("delimited file previews", () => { |
| 21 | 21 | ["", "three"], |
| 22 | 22 | ]); |
| 23 | 23 | }); |
| 24 | describe.each([",", "\t"] as const)("with delimiter %j", (delimiter) => { |
| 25 | it("preserves a final quoted empty record without requiring a line ending", () => { |
| 26 | for (const ending of ["", "\n", "\r\n"]) { |
| 27 | expect(parseDelimitedPreview(`name\r\nAlice\r\n""${ending}`, delimiter)).toEqual({ |
| 28 | rows: [["name"], ["Alice"], [""]], |
| 29 | truncated: false, |
| 30 | }); |
| 31 | } |
| 32 | expect(parseDelimitedPreview('""', delimiter)).toEqual({ |
| 33 | rows: [[""]], |
| 34 | truncated: false, |
| 35 | }); |
| 36 | }); |
| 37 | it("does not invent records for empty input or a trailing line ending", () => { |
| 38 | for (const prefix of ["", "\ufeff"]) { |
| 39 | expect(parseDelimitedPreview(prefix, delimiter).rows).toEqual([]); |
| 40 | expect(parseDelimitedPreview(`${prefix}name\r\n`, delimiter).rows).toEqual([["name"]]); |
| 41 | expect(parseDelimitedPreview(`${prefix}""`, delimiter).rows).toEqual([[""]]); |
| 42 | } |
| 43 | }); |
| 44 | it("keeps a quoted empty record at the row limit", () => { |
| 45 | const text = `${"name\n".repeat(99)}""`; |
| 46 | const preview = parseDelimitedPreview(text, delimiter); |
| 47 | expect(preview.rows).toHaveLength(100); |
| 48 | expect(preview.rows.at(-1)).toEqual([""]); |
| 49 | expect(preview.truncated).toBe(false); |
| 50 | expect(parseDelimitedPreview(`${text}\nextra`, delimiter).truncated).toBe(true); |
| 51 | }); |
| 52 | }); |
| 24 | 53 | it("bounds rows, columns and cell length and reports partial content", () => { |
| 25 | 54 | const table = parseDelimitedPreview( |
| 26 | 55 | Array.from({ length: 101 }, () => |