csv_plus 1.0.1
csv_plus: ^1.0.1 copied to clipboard
Fast, complete CSV parser for Dart. Encode, decode, stream, query, and validate CSV data with automatic type inference and zero dependencies.
1.0.1 #
Documentation and metadata only; no library or API changes.
- Reworked the README (clearer structure, added the logo screenshot, and broader keyword coverage) and refined the pub.dev topics for discoverability.
- Switched the head-to-head benchmark to compare against serial_csv in place of fast_csv.
1.0.0 #
First stable release: one documented parsing semantics across every decode path, streaming you can trust, data-loss guards on type inference, and public benchmark receipts. The API is now frozen under semantic versioning.
One parsing semantics (breaking behavior alignments) #
The batch decoder, string decoder, and streaming decoder previously
disagreed on edge cases. All paths now produce identical output,
enforced by a conformance suite that also splits input at every chunk
boundary (test/conformance_test.dart).
- An empty line reads as a row with one empty field (
[''], or[null]with typing), per RFC 4180 and matching csv 8 and fast_csv. WithskipEmptyLines(default), rows of a single empty field are dropped; rows of several empty fields (,,) are now always kept (previouslydecodeStringsdropped them). - Text after a closing quote is appended to the field, so
"a"xreadsax(Excel behavior). Previously the batch decoder produced an extra cell and the streaming decoder swallowed the following delimiter. - With
hasHeader, the header row is read as raw strings on every path: a header cell01stays01(previously typed then stringified to1), anddecoderTransformis not applied to it. - Quoted fields are never type-inferred on any path.
Type inference guards (data safety) #
FastDecoder.inferType is now the single shared inference used by all
typed paths, with guards against silent corruption:
- Leading zeros (
007), leading plus (+1), and surrounding whitespace stay text (previously' 42'typed differently per path). - Digit runs longer than 15 stay text on every platform, keeping VM and web results identical (web ints lose precision past 2^53).
- Values that would parse to a non-finite double (
1e999) stay text.
Typed decoders no longer invent data (breaking) #
decodeIntegers/decodeDoubles/decodeBooleansthrowCsvParseException(with row and column) on invalid cells instead of coercing them; empty cells throw unless an explicitemptyAs:fill is passed (previously empty became0/0.0and any non-truevalue becamefalse).decodeBooleanstruth table is documented and case-insensitive:true/1andfalse/0.decodeFlexibleusesconfig.quoteCharacterwhen restoring an unmatched quote (previously hardcoded"), and reads empty fields as''instead ofnullwhen typing is off.
Streaming you can trust #
CsvDecoder.bindandCsvEncoder.bindhonor downstream backpressure (pause/resume/cancel propagate to the source), so a slow consumer no longer buffers the whole input in memory, and the output stream closes after an upstream error instead of hanging.- Multi-character delimiters split across chunk boundaries now parse correctly (previously they became field text).
- New
CsvDecoder.bindBytes/CsvEncoder.bindBytesfor UTF-8 byte streams without manualutf8wiring. CsvFile.writeStreamcloses the file even when the source stream errors.
New: strict mode #
CsvConfig(strict: true) throws CsvParseException with row and
column on structurally malformed input (text after a closing quote,
unterminated quote) instead of recovering. Lenient stays the default.
Fixed #
decodeWithHeadersparsed the entire input twice; it is now single pass and roughly twice as fast (fastest in the ecosystem on this workload, previously the single lost benchmark).CsvTable.maphanded live row lists to its transform, so writing through the row mutated the source table. The transform now receives a copy; the source is never modified.- Delimiter autodetect no longer misreads single-column text containing semicolons as two columns: a candidate must appear on every sampled line to qualify (csv 8 still has this failure).
CsvTable.parseheaders are raw strings (01stays01).- All table sorts are stable, and nulls sort last in both directions.
Mixed-type columns sort numbers before string look-alikes instead of
comparing
"10" < "9"lexicographically. distinct()keys are type-aware (1,1.0, and"1"are distinct) and immune to separator collisions in string content.encodeGeneric<String>quotes strings containing delimiters instead of producing corrupt CSV;QuoteMode.alwayswrites null as"".- Batch and streaming encoders share one cell-writing implementation.
Changed #
ColumnDefis renamedCsvColumnDef(a deprecated typedef keeps old code compiling).DelimiterDetectorleft the defaultcsv_plus.dartnamespace; importpackage:csv_plus/decoder.dartto use it directly.CsvTabledocuments its mutation rule: table-returning methods copy, void methods mutate in place. New stablesortedBy()returns a sorted copy.- Releases are gated: the publish workflow now runs format, analyze, tests, and a publish dry-run before tagging or publishing, and CI runs a stable + minimum SDK matrix plus wasm and pana jobs.
Benchmarks #
Fastest on every measured workload (decode, typed decode, autodetect,
quote-heavy, encode, decodeWithHeaders) against csv 8.0.0,
fast_csv 0.2.11, and serial_csv 0.5.2, on JIT and AOT. The reproducible
harness and full tables live in benchmark/compare/.
0.0.2 #
Documentation #
- Redesigned README with hero layout, badges, feature table, and quick start examples
- Added 8 mini-library files for dartdoc sidebar navigation (core, codec, encoder, decoder, table, query, transform, io)
- Enhanced barrel export
lib/csv_plus.dartwith library modules reference
Meta #
- Added MIT LICENSE file
- SEO-optimized pubspec description and topics for pub.dev
- Added CI workflow (analyze, format, test on PRs)
- Added publish workflow (auto-tag + publish to pub.dev)
0.0.1 #
Core #
CsvConfig: immutable configuration with presets:CsvConfig(),.excel(),.tsv(),.pipe()CsvConfig.copyWith(): create modified copiesQuoteModeenum:necessary,always,stringsCsvException,CsvParseException,CsvValidationException: typed error hierarchy
Encoding #
FastEncoder: high-performance batch encoder withencode(),encodeStrings(),encodeGeneric<T>(),encodeMap()CsvEncoder: streaming encoder asStreamTransformerwithbind(),convert(),startChunkedConversion()CsvEncoder.encodeField(): static helper for single-field quoting- codeUnit-based
_needsQuoting()for multi-char delimiter support
Decoding #
FastDecoder: byte-level batch decoder withcodeUnitsparsing, labeled-loop control flow, first-byte type inference- Decode variants:
decode(),decodeStrings(),decodeFlexible(),decodeIntegers(),decodeDoubles(),decodeBooleans() CsvDecoder: chunked state-machine streaming decoder withbind(),convert(),startChunkedConversion()- Handles chunk boundaries splitting mid-field, mid-escape, mid-CRLF
DelimiterDetector: frequency/consistency scoring across candidates[, ; \t |], BOM strip,sep=hint
Facade #
CsvCodec: main API with all decode/encode methods, presets, auto-detectionCsvCodec.decodeToTable(),decodeMap(),encodeMap()CsvCodec.decoder/encoder: streaming transformer gettersCsvCodecAdapter:Codec<List<List<dynamic>>, String>fordart:convertpipelines and.fuse()csvPlus,csvExcel,csvTsv: global convenience instances
CsvTable (50+ methods) #
- Constructors:
CsvTable(),.withHeaders(),.fromData(),.fromMaps(),.parse(),.empty() - Access:
operator [],cell(),cellByName(),setCell(),setCellByName(),column(),columnAt(),getColumn(),getColumnAt() - Row ops:
addRow(),addRowFromMap(),addRows(),insertRow(),removeRow(),removeWhere() - Column ops:
addColumn(),insertColumn(),removeColumn(),removeColumnAt(),renameColumn(),reorderColumns() - Query:
where(),firstWhere(),any(),every(),range(),take(),skip(),distinct() - Sort:
sortBy(),sortByIndex(),sortByMultiple(),sort() - Transform:
transformColumn(),map(),fold<T>() - Aggregate:
count(),sum(),avg(),min(),max(),groupBy() - Export:
toList(),toMaps(),toCsv(),toString(),toFormattedString(),copy() - Validation:
validate(),conformsTo(),inferSchema()
CsvRow #
- Dual-mode access:
row[0](int) androw['name'](String) set(),headerMap,hasHeaders,headers,containsHeader(),toMap(),getHeaderName(),toString()
CsvColumn #
- Column descriptor with
name,index,values,inferredType,nonNullCount,nullCount,uniqueCount
CsvSchema & ColumnDef #
- Schema definition with
columns,allowExtraColumns,allowMissingColumns CsvSchema.infer(): infer types and nullability from datavalidate(): check required columns, types, nullability, patterns, custom validatorsColumnDefwithname,type,required,nullable,pattern,validator
CsvFile (dart:io) #
- Static methods:
read(),readSync(),stream(),write(),writeSync(),writeRows(),writeStream(),append() - Uses
utf8.decoderfor stream operations - Isolated in
io/csv_file.dart: core library stays platform-independent
