Skills csv-parse

install
source · Clone the upstream repo
git clone https://github.com/TerminalSkills/skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/TerminalSkills/skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/csv-parse" ~/.claude/skills/terminalskills-skills-csv-parse && rm -rf "$T"
manifest: skills/csv-parse/SKILL.md
source content

csv-parse

Parse and stringify CSV data. Streaming architecture handles files of any size.

Setup

# Install the csv package (includes parse, stringify, transform, generate).
npm install csv
# Or install individual packages:
npm install csv-parse csv-stringify

Parsing a CSV File

// src/csv/parse-file.ts — Read a CSV file and convert rows to objects.
// Uses the header row as keys for each record object.
import { parse } from "csv-parse";
import fs from "fs";

export async function parseCsvFile(filePath: string): Promise<Record<string, string>[]> {
  const records: Record<string, string>[] = [];

  const parser = fs.createReadStream(filePath).pipe(
    parse({
      columns: true,       // use first row as headers
      skip_empty_lines: true,
      trim: true,
    })
  );

  for await (const record of parser) {
    records.push(record);
  }

  return records;
}

Parsing a CSV String

// src/csv/parse-string.ts — Parse CSV data from a string (e.g., API response body).
import { parse } from "csv-parse/sync";

export function parseCsvString(csvData: string) {
  return parse(csvData, {
    columns: true,
    skip_empty_lines: true,
    cast: true,           // auto-cast numbers and booleans
    cast_date: true,      // auto-cast ISO date strings
  });
}

Generating CSV Output

// src/csv/stringify.ts — Convert objects to CSV strings for download or file export.
import { stringify } from "csv-stringify/sync";

interface SalesRow {
  product: string;
  revenue: number;
  units: number;
  date: string;
}

export function generateCsv(data: SalesRow[]): string {
  return stringify(data, {
    header: true,
    columns: [
      { key: "product", header: "Product Name" },
      { key: "revenue", header: "Revenue ($)" },
      { key: "units", header: "Units Sold" },
      { key: "date", header: "Date" },
    ],
  });
}

Streaming Large Files

// src/csv/stream.ts — Process million-row CSV files without loading into memory.
// Transform each record as it streams through.
import { parse } from "csv-parse";
import { stringify } from "csv-stringify";
import { transform } from "stream-transform";
import fs from "fs";

export function transformCsv(inputPath: string, outputPath: string) {
  fs.createReadStream(inputPath)
    .pipe(parse({ columns: true }))
    .pipe(
      transform((record: any) => ({
        name: record.name.toUpperCase(),
        email: record.email.toLowerCase(),
        total: Number(record.price) * Number(record.quantity),
      }))
    )
    .pipe(stringify({ header: true }))
    .pipe(fs.createWriteStream(outputPath));
}

Custom Delimiters

// src/csv/delimiters.ts — Handle TSV files, semicolon-separated, or pipe-delimited.
import { parse } from "csv-parse/sync";

// Tab-separated values
const tsvData = "name\tage\tcity\nAlice\t30\tPrague";
const tsvRecords = parse(tsvData, { columns: true, delimiter: "\t" });

// Semicolon-separated (common in European exports)
const csvData = "name;age;city\nAlice;30;Prague";
const csvRecords = parse(csvData, { columns: true, delimiter: ";" });

Validation

// src/csv/validate.ts — Validate CSV records during parsing and collect errors.
import { parse } from "csv-parse";
import fs from "fs";

interface ValidationError {
  line: number;
  field: string;
  message: string;
}

export async function validateCsv(
  filePath: string,
  requiredFields: string[]
): Promise<{ valid: any[]; errors: ValidationError[] }> {
  const valid: any[] = [];
  const errors: ValidationError[] = [];

  const parser = fs.createReadStream(filePath).pipe(
    parse({ columns: true, skip_empty_lines: true })
  );

  let line = 1;
  for await (const record of parser) {
    line++;
    let hasError = false;

    for (const field of requiredFields) {
      if (!record[field] || record[field].trim() === "") {
        errors.push({ line, field, message: `Missing required field: ${field}` });
        hasError = true;
      }
    }

    if (!hasError) valid.push(record);
  }

  return { valid, errors };
}

Express API Endpoint

// src/csv/api.ts — API endpoint that generates and streams a CSV download.
import { stringify } from "csv-stringify";
import type { Request, Response } from "express";

export function handleCsvExport(req: Request, res: Response, data: any[]) {
  res.setHeader("Content-Type", "text/csv");
  res.setHeader("Content-Disposition", "attachment; filename=export.csv");

  const stringifier = stringify({ header: true });
  stringifier.pipe(res);

  for (const row of data) {
    stringifier.write(row);
  }

  stringifier.end();
}