A comprehensive CSV (Comma-Separated Values) parsing and stringification library for MoonBit, migrated from the Deno standard library with full RFC 4180 compliance.
- âś… RFC 4180 Compliant: Full support for CSV specification including proper quote handling
- âś… Quoted Fields: Handle fields containing separators, quotes, and newlines
- âś… Quote Escaping: Proper handling of escaped quotes (
""
becomes"
) - âś… Multiple Line Endings: Support for LF (
\n
), CRLF (\r\n
), and CR (\r
) - âś… BOM Detection: Automatic handling of Byte Order Mark (
\ufeff
) - âś… Comment Lines: Skip lines starting with a comment character
- âś… Custom Separators: Support any separator (comma, semicolon, tab, etc.)
- âś… Flexible Field Validation: Optional field count validation per row
- âś… Lazy Quotes: Option to allow unescaped quotes in fields
- âś… Leading Space Trimming: Optional trimming of leading whitespace
- âś… Object Parsing: Convert CSV to array of objects using headers
- âś… Automatic Quoting: Fields containing separators, quotes, or newlines are automatically quoted
- âś… Quote Escaping: Proper escaping of quotes in output
- âś… CRLF Line Endings: Uses
\r\n
as per RFC 4180 - âś… BOM Support: Optional Byte Order Mark for Unicode compatibility
- âś… Custom Separators: Support any separator for output
- âś… Object Support: Convert arrays of objects to CSV with column control
- âś… Header Control: Optional headers in output
test "basic parsing example" {
let csv_data = "name,age,city\njohn,30,nyc\nmary,25,la"
let rows = @csv.parse(csv_data)
inspect(rows.length(), content="3")
inspect(rows[0], content=["name", "age", "city"])
inspect(rows[1], content=["john", "30", "nyc"])
}
test "parsing with options" {
let csv_data = "# Comment line\nname;age;city\njohn;30;nyc"
let options = @csv.ParseOptions::{
separator: ";",
comment: Some("#"),
skip_first_row: false,
}
let rows = @csv.parse_with_options(csv_data, options)
inspect(rows.length(), content="2") // Comment line skipped
}
test "advanced parsing" {
let csv_data = " \"john, jr\" , 30 , \"new\nyork\" "
let options = @csv.AdvancedParseOptions::{
separator: ",",
comment: None,
trim_leading_space: true,
lazy_quotes: false,
fields_per_record: -1,
skip_first_row: false,
columns: None,
}
let rows = @csv.parse_with_advanced_options(csv_data, options)
// Properly handles quoted fields with separators and newlines
inspect(rows[0], content=["john, jr", "30", "new\nyork"])
}
test "object parsing" {
let csv_data = "name,age,city\njohn,30,nyc\nmary,25,la"
let options = @csv.ParseOptions::{
separator: ",",
comment: None,
skip_first_row: true, // Use first row as headers
}
let objects = @csv.parse_to_objects(csv_data, Some(options))
inspect(objects.length(), content="2")
inspect(objects[0].get("name"), content=Some("john"))
inspect(objects[0].get("age"), content=Some("30"))
}
test "basic stringification" {
let data = [
["name", "age", "city"],
["john", "30", "nyc"],
["mary", "25", "la"],
]
let csv_output = @csv.stringify(data)
inspect(csv_output, content="name,age,city\r\njohn,30,nyc\r\nmary,25,la\r\n")
}
test "object stringification" {
let data = [
@Map.from_array([("name", "john"), ("age", "30"), ("city", "nyc")]),
@Map.from_array([("name", "mary"), ("age", "25"), ("city", "la")]),
]
let columns = ["name", "age", "city"]
let csv_output = @csv.stringify_with_columns(data, columns)
inspect(csv_output, content="name,age,city\r\njohn,30,nyc\r\nmary,25,la\r\n")
}
test "special characters" {
let data = [
["name", "description"],
["john", "a \"nice\" person"],
["mary", "lives in, NYC"],
["bob", "address:\n123 Main St"],
]
let csv_output = @csv.stringify(data)
// Automatically quotes fields with special characters
// Properly escapes quotes as ""
}
Parse CSV string with default options.
Parse CSV string with basic options.
Parse CSV string with all advanced features.
Parse CSV string to array of objects using headers.
Convert array of arrays to CSV string with default options.
Convert array of arrays to CSV string with options.
stringify_objects(data: Array[Map[String, String]], columns: Array[String]?, options: StringifyOptions?) -> String
Convert array of objects to CSV string.
Convert array of objects to CSV string with specified columns.
Basic parsing options for backward compatibility:
separator: String
- Field separator (default:","
)comment: String?
- Comment line prefix (default:None
)skip_first_row: Bool
- Skip first row for headers (default:false
)
Advanced parsing options with all features:
separator: String
- Field separator (default:","
)comment: String?
- Comment line prefix (default:None
)trim_leading_space: Bool
- Trim leading whitespace (default:false
)lazy_quotes: Bool
- Allow unescaped quotes (default:false
)fields_per_record: Int
- Field count validation (default:-1
for any)skip_first_row: Bool
- Skip first row for headers (default:false
)columns: Array[String]?
- Header column names (default:None
)
Stringification options:
separator: String
- Field separator (default:","
)headers: Bool
- Include headers (default:true
)bom: Bool
- Include BOM (default:false
)
This library fully implements RFC 4180 specification:
- CRLF Line Endings: Uses
\r\n
for line breaks - Quote Escaping: Doubles quotes (
""
) to escape them - Field Quoting: Automatically quotes fields containing separators, quotes, or newlines
- Header Support: Optional header row handling
- Empty Fields: Proper handling of empty fields
- Unicode Support: BOM detection and proper Unicode handling
The library provides detailed error messages with line and column information for parsing errors:
- Syntax Errors: Reports exact line and column of parsing issues
- Quote Errors: Specific messages for unescaped or malformed quotes
- Field Count Errors: Clear messages when field count validation fails
- Invalid Delimiters: Prevents use of invalid separator or comment characters
This library is migrated from the Deno standard library's CSV module, ensuring:
- Feature parity with the TypeScript implementation
- RFC 4180 compliance
- Comprehensive test coverage (45+ test cases)
- Performance optimization for MoonBit
- Proper error handling with MoonBit's type system
The library includes comprehensive test coverage:
- Basic parsing and stringification
- RFC 4180 compliance tests
- Edge cases (BOM, empty fields, quotes)
- Advanced features (lazy quotes, trimming, validation)
- Integration tests (round-trip parsing/stringification)
- Error condition handling
Run tests with:
moon test