CsvParseStream

import { CsvParseStream } from "jsr:@ende/csv";

class

class CsvParseStream<T extends CsvParseStreamOptions | undefined = undefined> implements TransformStream<string, RowType<T>>

CsvParseStream transforms a stream of CSV-encoded text into a stream of parsed objects.

A CsvParseStream expects input conforming to RFC 4180.

Example: Usage with default options

import { CsvParseStream } from "@ende/csv/parse-stream";
import { assertEquals } from "@ende/assert/equals";
import { assertType, IsExact } from "@ende/testing/types"

const source = ReadableStream.from([
  "name,age\n",
  "Alice,34\n",
  "Bob,24\n",
]);
const stream = source.pipeThrough(new CsvParseStream());
const result = await Array.fromAsync(stream);

assertEquals(result, [
  ["name", "age"],
  ["Alice", "34"],
  ["Bob", "24"],
]);
assertType<IsExact<typeof result, string[][]>>(true);

Example: Skip first row with skipFirstRow: true

import { CsvParseStream } from "@ende/csv/parse-stream";
import { assertEquals } from "@ende/assert/equals";
import { assertType, IsExact } from "@ende/testing/types"

const source = ReadableStream.from([
  "name,age\n",
  "Alice,34\n",
  "Bob,24\n",
]);
const stream = source.pipeThrough(new CsvParseStream({ skipFirstRow: true }));
const result = await Array.fromAsync(stream);

assertEquals(result, [
  { name: "Alice", age: "34" },
  { name: "Bob", age: "24" },
]);
assertType<IsExact<typeof result, Record<string, string>[]>>(true);

Example: Specify columns with columns option

import { CsvParseStream } from "@ende/csv/parse-stream";
import { assertEquals } from "@ende/assert/equals";
import { assertType, IsExact } from "@ende/testing/types"

const source = ReadableStream.from([
  "Alice,34\n",
  "Bob,24\n",
]);
const stream = source.pipeThrough(new CsvParseStream({
  columns: ["name", "age"]
}));
const result = await Array.fromAsync(stream);

assertEquals(result, [
  { name: "Alice", age: "34" },
  { name: "Bob", age: "24" },
]);
assertType<IsExact<typeof result, Record<"name" | "age", string>[]>>(true);

Example: Specify columns with columns option and skip first row with

skipFirstRow: true

import { CsvParseStream } from "@ende/csv/parse-stream";
import { assertEquals } from "@ende/assert/equals";
import { assertType, IsExact } from "@ende/testing/types"

const source = ReadableStream.from([
  "Alice,34\n",
  "Bob,24\n",
]);
const stream = source.pipeThrough(new CsvParseStream({
  columns: ["name", "age"],
  skipFirstRow: true,
}));
const result = await Array.fromAsync(stream);

assertEquals(result, [{ name: "Bob", age: "24" }]);
assertType<IsExact<typeof result, Record<"name" | "age", string>[]>>(true);

Example: TSV (tab-separated values) with separator: "\t"

import { CsvParseStream } from "@ende/csv/parse-stream";
import { assertEquals } from "@ende/assert/equals";

const source = ReadableStream.from([
  "Alice\t34\n",
  "Bob\t24\n",
]);
const stream = source.pipeThrough(new CsvParseStream({
  separator: "\t",
}));
const result = await Array.fromAsync(stream);

assertEquals(result, [
  ["Alice", "34"],
  ["Bob", "24"],
]);

Example: Trim leading space with trimLeadingSpace: true

import { CsvParseStream } from "@ende/csv/parse-stream";
import { assertEquals } from "@ende/assert/equals";

const source = ReadableStream.from([
  "      Alice,34\n          ",
  "Bob,     24\n",
]);
const stream = source.pipeThrough(new CsvParseStream({
  trimLeadingSpace: true,
}));
const result = await Array.fromAsync(stream);

assertEquals(result, [
  ["Alice", "34"],
  ["Bob", "24"],
]);

Example: Quoted fields

import { CsvParseStream } from "@ende/csv/parse-stream";
import { assertEquals } from "@ende/assert/equals";

const source = ReadableStream.from([
  `"a ""word""","com`,
  `ma,","newline`,
  `\n"\nfoo,bar,b`,
  `az\n`,
]);
const stream = source.pipeThrough(new CsvParseStream());
const result = await Array.fromAsync(stream);

assertEquals(result, [
  ['a "word"', "comma,", "newline\n"],
  ["foo", "bar", "baz"]
]);

Example: Allow lazy quotes with lazyQuotes: true

import { CsvParseStream } from "@ende/csv/parse-stream";
import { assertEquals } from "@ende/assert/equals";

const source = ReadableStream.from([
  `a "word","1"`,
  `2",a","b`,
]);
const stream = source.pipeThrough(new CsvParseStream({
  lazyQuotes: true,
}));
const result = await Array.fromAsync(stream);

assertEquals(result, [['a "word"', '1"2', 'a"', 'b']]);

Example: Define comment prefix with comment option

import { CsvParseStream } from "@ende/csv/parse-stream";
import { assertEquals } from "@ende/assert/equals";

const source = ReadableStream.from([
  "Alice,34\n",
  "# THIS IS A COMMENT\n",
  "Bob,24\n",
]);
const stream = source.pipeThrough(new CsvParseStream({
  comment: "#",
}));
const result = await Array.fromAsync(stream);

assertEquals(result, [
  ["Alice", "34"],
  ["Bob", "24"],
]);

Example: Infer the number of fields from the first row with

fieldsPerRecord: 0

import { CsvParseStream } from "@ende/csv/parse-stream";
import { assertEquals } from "@ende/assert/equals";
import { assertRejects } from "@ende/assert/rejects";

const source = ReadableStream.from([
  "Alice,34\n",
  "Bob,24,CA\n", // Note that this row has more fields than the first row
]);
const stream = source.pipeThrough(new CsvParseStream({
  fieldsPerRecord: 0,
}));
const reader = stream.getReader();
assertEquals(await reader.read(), { done: false, value: ["Alice", "34"] });
await assertRejects(
  () => reader.read(),
  SyntaxError,
  "Syntax error on line 2: expected 2 fields but got 3",
);

Example: Enforce the number of field for each row with fieldsPerRecord: 2

import { CsvParseStream } from "@ende/csv/parse-stream";
import { assertEquals } from "@ende/assert/equals";
import { assertRejects } from "@ende/assert/rejects";

const source = ReadableStream.from([
  "Alice,34\n",
  "Bob,24,CA\n",
]);
const stream = source.pipeThrough(new CsvParseStream({
  fieldsPerRecord: 2,
}));
const reader = stream.getReader();
assertEquals(await reader.read(), { done: false, value: ["Alice", "34"] });
await assertRejects(
  () => reader.read(),
  SyntaxError,
  "Syntax error on line 2: expected 2 fields but got 3",
);

Constructors

constructor

new CsvParseStream(options?: T)

Construct a new instance.

options?: T

Options for the stream.

Methods

readable

get readable(): ReadableStream<RowType<T>>

The instance's ReadableStream.

Returns

The instance's ReadableStream.

Example: Usage

import { CsvParseStream } from "@ende/csv/parse-stream";
import { assertEquals } from "@ende/assert/equals";

const source = ReadableStream.from([
  "name,age\n",
  "Alice,34\n",
  "Bob,24\n",
]);
const parseStream = new CsvParseStream({ skipFirstRow: true });
const parts = source.pipeTo(parseStream.writable);
assertEquals(await Array.fromAsync(parseStream.readable), [
  { name: "Alice", age: "34" },
  { name: "Bob", age: "24" },
]);

writable

get writable(): WritableStream<string>

The instance's WritableStream.

Returns

The instance's WritableStream.

Example: Usage

import { CsvParseStream } from "@ende/csv/parse-stream";
import { assertEquals } from "@ende/assert/equals";

const source = ReadableStream.from([
  "name,age\n",
  "Alice,34\n",
  "Bob,24\n",
]);
const parseStream = new CsvParseStream({ skipFirstRow: true });
const parts = source.pipeTo(parseStream.writable);
assertEquals(await Array.fromAsync(parseStream.readable), [
  { name: "Alice", age: "34" },
  { name: "Bob", age: "24" },
]);

Source