diff --git a/csv/_io.ts b/csv/_io.ts index 46082fb5c105..2a6742edfa26 100644 --- a/csv/_io.ts +++ b/csv/_io.ts @@ -64,7 +64,7 @@ export async function parseRecord( opt: ReadOptions, startLine: number, lineIndex: number = startLine, -): Promise | null> { +): Promise> { // line starting with comment character is ignored if (opt.comment && line[0] === opt.comment) { return []; diff --git a/csv/csv_parse_stream.ts b/csv/csv_parse_stream.ts index fae4b5daab79..a7f2051e7782 100644 --- a/csv/csv_parse_stream.ts +++ b/csv/csv_parse_stream.ts @@ -150,11 +150,6 @@ export class CsvParseStream< this.#options, this.#lineIndex, ); - if (record === null) { - controller.close(); - this.#lineReader.cancel(); - return; - } if (this.#isFirstRow) { this.#isFirstRow = false; diff --git a/csv/csv_parse_stream_test.ts b/csv/csv_parse_stream_test.ts index d6ca95b77b56..ea9c014f63fe 100644 --- a/csv/csv_parse_stream_test.ts +++ b/csv/csv_parse_stream_test.ts @@ -87,6 +87,12 @@ Deno.test({ output: [["a", "b", "c"]], separator: ";", }, + { + name: "Separator is undefined", + input: "a;b;c\n", + errorMessage: "Separator is required", + separator: undefined, + }, { name: "MultiLine", input: `"two @@ -108,6 +114,12 @@ field"`, input: " a, b, c\n", output: [[" a", " b", " c"]], }, + { + name: "trimLeadingSpace = true", + input: " a, b, c\n", + output: [["a", "b", "c"]], + trimLeadingSpace: true, + }, { name: "Comment", input: "#1,2,3\na,b,c\n#comment", @@ -310,22 +322,45 @@ x,,, errorMessage: "Error number of fields line: 1\nNumber of fields found: 3\nExpected number of fields: 2", }, + { + name: "bad quote in bare field", + input: `a "word",1,2,3`, + errorMessage: "Error line: 1\nBad quoting", + }, + { + name: "bad quote in quoted field", + input: `"wo"rd",1,2,3`, + errorMessage: "Error line: 1\nBad quoting", + }, + { + name: "lazy quote", + input: `a "word","1"2",a","b`, + output: [[`a "word"`, `1"2`, `a"`, `b`]], + lazyQuotes: true, + }, ]; for (const testCase of testCases) { await t.step(testCase.name, async () => { const options: CsvParseStreamOptions = {}; - if (testCase.separator) { + if ("separator" in testCase) { options.separator = testCase.separator; } - if (testCase.comment) { + if ("comment" in testCase) { options.comment = testCase.comment; } - if (testCase.skipFirstRow) { + if ("skipFirstRow" in testCase) { options.skipFirstRow = testCase.skipFirstRow; } - if (testCase.columns) { + if ("columns" in testCase) { options.columns = testCase.columns; } + if ("trimLeadingSpace" in testCase) { + options.trimLeadingSpace = testCase.trimLeadingSpace; + } + if ("lazyQuotes" in testCase) { + options.lazyQuotes = testCase.lazyQuotes; + } + const readable = ReadableStream.from(testCase.input) .pipeThrough(new CsvParseStream(options));