Skip to content
cstroliadavisPublic

About

Lightweight, zero-dependency streaming CSV library for Bun and modern JavaScript environments

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

csv-lib

A lightweight, zero-dependency CSV library built for Bun (v1.4.4+).

Handles RFC 4180-compliant parsing and writing, including multiline cells with newlines, embedded double quotes (""), custom delimiters, UTF-8 BOM, and chunk-by-chunk file streaming via native Web Streams.

Documentation

Resource Description
Developer Guide Deep-dive guides covering parsing, headers, stringifying, Web Streams, file I/O, and recipes.
Hands-On Tutorial Progressive 10-lesson course from first parse to building a streaming ETL pipeline.
API Reference Full TypeDoc HTML reference generated from JSDoc contracts (bun run docs).

Features

  • Zero Third-Party Dependencies: Uses only Bun's built-in APIs and standard Web Streams.
  • Streaming State Machine: Processes chunks of arbitrary sizes (even 1-byte chunks) without buffering full files in memory.
  • RFC 4180 Compliance: Correctly escapes embedded quotes ("" -> "), multiline cells containing \r\n or \n, commas, and whitespace.
  • Record Mapping: Easily transform rows into typed JavaScript objects ({ columns: true }).
  • High-Level File Helpers: readCsvFile, writeCsvFile, appendCsvFile, and streamCsvFile powered by Bun.file.
  • Web Streams: Native TransformStream implementations for parsing and stringifying.
  • Full TypeScript Support: Comprehensive types and strict type safety out of the box.

Installation & Setup

bun test

Quick Start

1. Simple Parsing & Stringifying

import { parseCsv, stringifyCsv } from './index.ts';

// Parse CSV text into 2D array of rows
const rows = parseCsv('name,score\nAlice,95\nBob,88');
// [ ['name', 'score'], ['Alice', '95'], ['Bob', '88'] ]

// Parse with header mapping into objects
const records = parseCsv('name,score\nAlice,95', { columns: true });
// [ { name: 'Alice', score: '95' } ]

// Serialize array of objects back to CSV
const csv = stringifyCsv([
  { age: 30, name: 'Alice' },
  { age: 25, name: 'Bob' },
]);

2. Streaming File Reading

Stream large files row by row without buffering the entire file:

import { streamCsvFile } from './index.ts';

for await (const row of streamCsvFile('large_dataset.csv', { columns: true })) {
  console.log(row.name, row.score);
}

3. File Writing & Appending

import { appendCsvFile, readCsvFile, writeCsvFile } from './index.ts';

// Write records with headers
await writeCsvFile('users.csv', [
  { city: 'Tokyo', name: 'Alice' },
  { city: 'London', name: 'Bob' },
]);

// Append new records (automatically omits duplicate header line)
await appendCsvFile('users.csv', [{ city: 'Paris', name: 'Charlie' }]);

// Read back entire file
const users = await readCsvFile('users.csv', { columns: true });

4. Embedded Quotes & Multiline Cells

import { parseCsv, stringifyCsv } from './index.ts';

const original = [
  ['Quote', 'Multiline Note'],
  ['He said "Hello!"', 'Line 1\nLine 2\nLine 3'],
];

const csv = stringifyCsv(original);
// Quote,Multiline Note
// "He said ""Hello!""","Line 1
// Line 2
// Line 3"

const parsed = parseCsv(csv);
// Perfectly roundtrips back to original data!

5. Web TransformStream Integration

Use standard Web Streams to pipe byte or text streams:

import { createCsvTransformStream } from './index.ts';

const response = await fetch('https://example.com/data.csv');
const transform = createCsvTransformStream({ columns: true });
const recordStream = response.body.pipeThrough(transform);

for await (const record of recordStream) {
  console.log(record);
}

API Reference

Parser Functions

  • parseCsv<T>(text: string, options?: CsvParserOptions): T[]
  • parseCsvStream<T>(source: AsyncIterable<string | Uint8Array>, options?: CsvParserOptions): AsyncGenerator<T>
  • createCsvParser(options?: CsvParserOptions): CsvParser

Stringifier Functions

  • stringifyCsv(data: CsvValue[][] | Record<string, CsvValue>[], options?: CsvStringifierOptions): string
  • stringifyCsvStream(items: AsyncIterable<CsvValue[] | Record<string, CsvValue>>, options?: CsvStringifierOptions): AsyncGenerator<string>
  • createCsvStringifier(options?: CsvStringifierOptions): CsvStringifier

Stream & Pipeline Functions

  • createCsvTransformStream<T>(options?: CsvParserOptions): TransformStream<Uint8Array | string, T>
  • createCsvFormatTransformStream(options?: CsvStringifierOptions): TransformStream<CsvValue[] | Record<string, CsvValue>, string>
  • createCsvReader<T>(source: AsyncIterable<Uint8Array | string>, options?: CsvParserOptions): CsvReader<T>
  • createCsvWriter(destination: string | WritableStream, options?: CsvStringifierOptions): CsvWriter

File Operations (Bun.file)

  • readCsvFile<T>(filePath: string, options?: CsvParserOptions): Promise<T[]>
  • streamCsvFile<T>(filePath: string, options?: CsvParserOptions): AsyncGenerator<T>
  • writeCsvFile(filePath: string, data: ... , options?: CsvStringifierOptions): Promise<number>
  • appendCsvFile(filePath: string, data: ... , options?: CsvStringifierOptions): Promise<void>

Building for Distribution

Build the production ESM bundle and TypeScript declaration files:

# Clean, bundle with Bun, and emit type declarations (.d.ts) into dist/
bun run build

The resulting dist/ directory contains:

  • dist/index.js: Self-contained ESM bundle with external source maps.
  • dist/index.d.ts: TypeScript entrypoint declaration.
  • dist/src/*.d.ts: Module declaration files.

Developer Documentation

Generate interactive HTML API documentation from JSDoc comments via TypeDoc:

# Generate HTML API reference into docs/api-reference/
bun run docs

# Watch mode for documentation development
bun run docs:watch

Testing, Linting & Formatting

All formatting, linting, typechecking, and test settings are consolidated in bunfig.toml:

# Run tests with Bun's native test runner
bun run test

# Run Bun's native linter (bun lint)
bun run lint

# Automatically fix lint errors (bun lint --fix)
bun run lint:fix

# Format code and Markdown files using Bun's native formatter (bun fmt)
bun run format

# Verify formatting without modifying files (bun fmt --check)
bun run format:check

# Run Bun's native TypeScript type checker (bun check)
bun run typecheck

About

Lightweight, zero-dependency streaming CSV library for Bun and modern JavaScript environments

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages