@origints/csv
v0.3.2
Published
CSV parsing and navigation for Origins with full lineage tracking
Downloads
237
Maintainers
Readme
@origints/csv
CSV parsing and navigation for Origins with full lineage tracking.
Features
- Parse CSV with RFC 4180 support (quoted fields, embedded newlines)
- Header row detection and column-by-name access
- Lazy row and column iteration via generators
- Type coercion (number, boolean) on demand
- JSON conversion with customizable options
- Custom delimiters, quote characters, comments, and trim
- Integrates with Origins transform registry
Installation
npm install @origints/csv @origints/coreUsage with Planner
Extract values from specific cells
import { Planner, loadFile, run } from '@origints/core'
import { parseCsv } from '@origints/csv'
const plan = new Planner()
.in(loadFile('users.csv'))
.mapIn(parseCsv({ header: true }))
.emit((out, $) =>
out
.add('firstName', $.row(0).col('name').string())
.add('firstAge', $.row(0).col('age').number())
)
.compile()
const result = await run(plan, { readFile, registry })
// result.value: { firstName: 'Alice', firstAge: 30 }Iterate over all rows
Use rows() to extract data from every row as an array:
// users.csv:
// name,age,active
// Alice,30,true
// Bob,25,false
const plan = new Planner()
.in(loadFile('users.csv'))
.mapIn(parseCsv({ header: true }))
.emit((out, $) =>
out.add(
'users',
$.rows(row => ({
kind: 'object',
properties: {
name: row.col('name').string(),
age: row.col('age').number(),
active: row.col('active').boolean(),
},
}))
)
)
.compile()
const result = await run(plan, { readFile, registry })
// result.value: {
// users: [
// { name: 'Alice', age: 30, active: true },
// { name: 'Bob', age: 25, active: false },
// ]
// }Index-based access (headerless CSV)
const plan = new Planner()
.in(loadFile('data.csv'))
.mapIn(parseCsv())
.emit((out, $) =>
out.add(
'pairs',
$.rows(row => ({
kind: 'object',
properties: {
key: row.at(0).string(),
value: row.at(1).string(),
},
}))
)
)
.compile()Combine CSV with other data sources
const plan = new Planner()
.in(loadFile('employees.csv'))
.mapIn(parseCsv({ header: true }))
.emit((out, $) =>
out.add(
'employees',
$.rows(row => row.col('name').string())
)
)
.in(loadFile('config.json'))
.mapIn(parseJson())
.emit((out, $) => out.add('department', $.get('department').string()))
.compile()Standalone usage (without Planner)
For direct CSV navigation and manipulation:
import { parseCsvText, CsvTable } from '@origints/csv'
const table = parseCsvText(
'name,age,email\nAlice,30,[email protected]\nBob,25,[email protected]',
{
header: true,
}
)
// Access rows
const row = table.row(0)
if (row.ok) {
console.log(row.value.col('name')) // ok: 'Alice'
console.log(row.value.fieldAsNumber('age')) // ok: 30
}
// Lazy iteration
for (const row of table) {
const email = row.col('email')
if (email.ok) console.log(email.value)
}
// Column extraction
for (const name of table.column('name')) {
console.log(name)
}
// Direct cell access
const cell = table.cell(1, 'email')
if (cell.ok) console.log(cell.value) // '[email protected]'
// Bulk materialization
const records = table.asRecords()
if (records.ok) console.log(records.value)
// [{ name: 'Alice', age: '30', ... }, { name: 'Bob', age: '25', ... }]Type coercion
const row = table.row(0)
if (row.ok) {
const age = row.value.fieldAsNumber('age')
if (age.ok) console.log(age.value) // 30
const active = row.value.fieldAsBoolean('active')
if (active.ok) console.log(active.value) // true
}JSON conversion
import { parseCsvText, toJson } from '@origints/csv'
const table = parseCsvText(csvString, { header: true })
// Convert to JSON with type coercion
const json = toJson(table, {
parseNumbers: true,
parseBooleans: true,
emptyAsNull: true,
})
if (json.ok) console.log(json.value)
// [{ name: 'Alice', age: 30, active: true }, ...]Parse options
parseCsvText(input, {
header: true, // First row is header
delimiter: ';', // Field delimiter (default: ',')
quoteChar: '"', // Quote character (default: '"')
escapeChar: '"', // Escape character (default: '"')
skipEmptyLines: true, // Skip blank rows
trimFields: true, // Trim whitespace from fields
comment: '#', // Lines starting with this char are skipped
})API
| Export | Description |
| ------------------------------------------------------------------------ | ----------------------------------------------------- |
| parseCsv(options?) | Create a transform AST for use with Planner.mapIn() |
| parseCsvText(input, options?) | Parse CSV string directly (standalone) |
| parseCsvImpl | Sync transform implementation (string input) |
| parseCsvAsyncImpl | Async transform implementation (string or stream) |
| registerCsvTransforms(registry) | Register all CSV transforms with a registry |
| CsvTable | Root table with row/column/cell access |
| CsvRow | Row wrapper with field access and type coercion |
| toJson(table, options?) | Convert CsvTable to JSON |
| toJsonValue(table) | Convert CsvTable to JSON with defaults |
| ok, parseFail, typeFail, missingFail, boundsFail, headerFail | Result helpers |
| formatCsvPath | Format path for display |
License
MIT
