Skip to content

Releases: TriasDev/tabular

v0.7.0

Choose a tag to compare

@github-actions github-actions released this 05 Oct 21:53
1a7696d

0.7.0 (2026-10-05)

Features

  • write: a workbook column is never narrower than its header (#115) (59dfdc4)

v0.6.0

Choose a tag to compare

@github-actions github-actions released this 05 Oct 16:25
2ded6b6

0.6.0 (2026-10-05)

⚠ BREAKING CHANGES

  • the concrete cursors (CsvCursor, XlsxCursor, OdsCursor, ArchiveCursor, GzipCursor) and CsvDialectDetector are internal, so TabularFile.Open is the only way to a cursor; every public type is in the TriasDev.Tabular namespace, the format options included; CsvCursorOptions.Dialect is replaced by the Delimiter, Encoding and Quote hints and CsvDialect is output-only; the writer reports its limits as TabularWriteException (write.too-many-rows, write.too-many-merges, write.too-many-styles) instead of TabularLimitException; row numbers are int on both sides (TabularExport returns ValueTask, AnalysisProgress.RowsRead is int); HorizontalAlignment is CellHorizontalAlignment, TabularWriter.Style is RegisterStyle, CellStyle.Number and Date are NumberFormat and DateFormat; NumberFormat.Parse and DateFormat.Parse throw FormatException; typed import fields come only from their factories; CursorDiagnostics has no public constructor.

Features

  • count a column's rows that fall in a set of values (5b773ae)
  • declare field groups as alternatives in priority order (d819eff)
  • hand a mapper the group that locates its row (5b6ba1d)
  • judge field alternatives per row during extraction (8adec9f)
  • precheck what a mapping decides about field alternatives (a27d6c6)
  • read gzip-compressed files as the file inside them (#80) (78e1223)
  • read tar and tar.gz archives as one workbook (#82) (faf0be7)
  • report how each set of alternatives covers the rows (d691f7c)
  • review a whole file through a mapping before importing it (ac2758c)
  • write: cell styles for xlsx and ods (#90) (45dbca8)
  • write: ColumnBatch — rows given by column, typed, with a style per column (#93) (13f2807)
  • write: sheet layout — header style, frozen panes, auto-filter, merged cells (#91) (c158848)
  • write: TabularExport<T> — an export declared once with typed columns (#84) (78f2379)
  • write: TabularFormat.Zip — a zip of csv sheets (#94) (1e8e23c)
  • write: write csv through TabularWriter, round-tripping through the import (#77) (5de3450)
  • write: write OpenDocument spreadsheets through TabularWriter (#83) (8567fa1)
  • write: write xlsx through TabularWriter, with our own streaming zip writer (#81) (6451e59)

Bug Fixes

  • an invalid value locates nothing, an unneeded one costs nothing, and the precheck does not block AllOrNothing for rows that import (547cc20)
  • archive: refuse a tar metadata entry that claims more than it can hold, instead of letting TarReader's InvalidOperationException escape (#99) (7363a42), closes #92
  • csv: find the delimiter when the dialect probe ends inside a multi-line quoted field (#101) (916adf8)
  • the deferred archive and OpenDocument findings (#102) (d88ea71)
  • write: keep a failed write's exception on close; sheet options for a declared export (#98) (0fea097)

Code Refactoring

  • the public API's last breaking window before 0.6.0 (#108) (8d6825a)

v0.5.0

Choose a tag to compare

@github-actions github-actions released this 29 Sep 16:32
4f3fc78

0.5.0 (2026-09-29)

Features

  • count the rows of every distinct value, and give precheck rule findings their exact affected rows (#64) (52ef740)

Bug Fixes

  • analysis: a date written with a culture's own separator ranks that culture first, and the facts say when date readings disagree (#59) (1fa72b3)
  • analysis: numbers that read under both separators rank the one the sheet's evidence favours, and the facts say when number readings disagree (#62) (8b14042)

v0.4.0

Choose a tag to compare

@github-actions github-actions released this 28 Sep 16:27
4dd9be2

0.4.0 (2026-09-28)

Features

  • count, and on request import, a decimal written with the other separator where it can be read no other way (42c26ad)
  • say whether a sheet is hidden, on SheetInfo and SheetProfile (#55) (88820a6)

Bug Fixes

  • analysis,import: read a decimal written in exponential notation, in the profile and the import alike (#52) (b174704)
  • analysis: empty cells past a row's last value are padding, not columns (#53) (f9783ba)
  • analysis: when the distinct budget runs out, settled and rightmost columns give theirs up, so the key keeps an answer (#54) (eea4c64)
  • csv: a quoted value whose line would overfill the record is not read as a stray quote (69a7b47)
  • mapping: a pattern on the linear engine runs without a clock, so a valid value cannot fail on a slow first match (994cb1f)
  • xlsx,ods: read a line end written as it is the way XML does, as a line feed (fc203bb)
  • xlsx: a number format counts only inside numFmts, not in a conditional format's dxf (43cbda2)
  • xlsx: decode the xHHHH escapes OOXML writers use for characters in strings (6b1b0b4)
  • xlsx: read a boolean cell holding no xsd:boolean as its text, not as false (58f7eb3)
  • xlsx: read a boolean written as true or false, as the Open XML SDK writes it (b13a703)
  • xlsx: read a value on past text that follows a CDATA section (9b0d785)

Performance Improvements

  • the other-separator check runs only on values that could be numbers, with the separator looked up once (b9ba1c5)

v0.3.0

Choose a tag to compare

@github-actions github-actions released this 27 Sep 13:26
1ca8665

0.3.0 (2026-09-27)

⚠ BREAKING CHANGES

  • TabularExtractor.Start → TabularExtractor.Extract, and ExtractionSession → ExtractionRun; its members are unchanged.
  • precheck argument keys renamed — readableCount → judgedCount (PrecheckArguments.ReadableCount → JudgedCount), profileHeaderRow → profileHeaderRowIndex, planHeaderRow → planHeaderRowIndex, boundColumns → boundColumnCount. A schema with a typed field whose Type is not its class's is refused with ArgumentException. The constraints, now classes, no longer have init setters on Length and Value.
  • the public API is reshaped once for 1.0. Old → new:
    • new TabularAnalyzer(options).Analyze(cursor, progress, ct) → TabularAnalyzer.Analyze(cursor, options, progress, ct)
    • TargetField → ImportField (also the factory: ImportField.Text(...) and the others)
    • TextField / IntegerField / DecimalField / DateField / BooleanField → TextImportField / IntegerImportField / DecimalImportField / DateImportField / BooleanImportField
    • TranslatedField → TranslatedImportField; TargetSchema → ImportSchema
    • SourceColumnIndex → ColumnIndex and TargetFieldName → FieldName on ColumnBinding, RowError, MappingFault, PrecheckFinding; TabularStructureException.SourceColumnIndex → ColumnIndex; ColumnBinding.SourceHeader → Header
    • new ITabularProblem, implemented by RowError, MappingFault, PrecheckFinding
    • PrecheckFinding.Detail removed → AffectedRowsBound, Examples, Arguments (PrecheckArguments, PrecheckReasons); PrecheckFinding.FieldName / ColumnIndex are nullable
    • foreach (var o in run) → run.ReadRows(ct); Rows → ReadRows, InChunks → ReadChunks, All → ReadAll; ImportRun<T> is not an IEnumerable
    • ExtractionSummary is an immutable record; Summary properties return snapshots
    • fields, ImportSchema and constraints are classes (no with, reference equality); plans, bindings, options, profiles and results compare by value; CursorDiagnostics is a record
    • ITabularCursor.MoveToSheet(int) → MoveToSheet(int, CancellationToken = default)
  • ITabularCursor.MoveToSheet(int) is MoveToSheet(int, CancellationToken = default); a cursor implemented outside the library must add the parameter.
  • ImportRun no longer implements IEnumerable; foreach (var o in run) is foreach (var o in run.ReadRows(ct)). Rows → ReadRows, InChunks → ReadChunks, All → ReadAll. ExtractionSummary is an immutable record: ImportRun.Summary and ExtractionSession.Summary return a snapshot rather than a live object.
  • ImportField (and TextImportField and the other typed fields), ImportSchema, FieldConstraint and its nested rules are classes, not records: with expressions, value equality and deconstruction on them are gone. CursorDiagnostics is a record. Collections in MappingPlan, ColumnBinding, AnalysisOptions, FileProfile, SheetProfile, ColumnProfile, ColumnFacts, CultureParseCounts, TypeHypothesis, PrecheckFinding, PrecheckResult, ImportPreviewRow and ImportResult compare by value.
  • PrecheckFinding.Detail is removed; its data is in AffectedRowsBound, Examples and Arguments. PrecheckFinding.FieldName is string? and ColumnIndex is int?, null where a finding concerns no field or column.
  • renamed types — TargetField → ImportField (now also the factory; the static class ImportField is merged into it), TextField → TextImportField, IntegerField → IntegerImportField, DecimalField → DecimalImportField, DateField → DateImportField, BooleanField → BooleanImportField, TranslatedField → TranslatedImportField, TargetSchema → ImportSchema. Renamed members — SourceColumnIndex → ColumnIndex and TargetFieldName → FieldName on ColumnBinding, RowError, MappingFault and PrecheckFinding; TabularStructureException.SourceColumnIndex → ColumnIndex; ColumnBinding.SourceHeader → Header. A plan stored with the old property names must be migrated.
  • new TabularAnalyzer(options).Analyze(cursor, progress, ct) is now TabularAnalyzer.Analyze(cursor, options, progress, ct); the constructor and the instance overloads are gone.

Features

  • an import run reads once, through ReadRows, ReadChunks or ReadAll (53a5248)
  • MoveToSheet takes a cancellation token (362737a)
  • precheck findings carry their data instead of an English sentence (d45f2ee)
  • TabularAnalyzer is static, its options passed to Analyze (47a84e7)

Bug Fixes

  • findings of the final reviews of the 1.0 API (b7e5bd3)

Documentation

  • the documentation follows the 1.0 API (f80cf99)

Code Refactoring

  • data compares by value; fields, constraints and schemas are classes (b947e0b)
  • TabularExtractor.Extract returns an ExtractionRun (4c53e2a)
  • unique names for fields and schemas; one shape for a problem (fec1071)

v0.2.0

Choose a tag to compare

@github-actions github-actions released this 26 Sep 15:05
6899f23

0.2.0 (2026-09-26)

Features

  • archive: open a zip archive by its contents (49cde9b)
  • archive: options, the zip format and skipped entries (a0aea63)
  • archive: read the csv files in a zip archive as sheets (59b086c)
  • archive: read xlsx and ods workbooks inside an archive (2bcdf09)
  • ods: read OpenDocument spreadsheets (5f5f927), closes #13

Bug Fixes

  • archive: findings of the final review (88bcd8f)
  • csv: read quoted notes of any length, catching stray quotes by what they swallow (b550474)
  • csv: refuse an XML document instead of reading its markup as lines (efd98fc)
  • drop the raw HTML image from the readme, which nuget.org shows as text (2ccdbbf)
  • ods: findings of two independent reviews (a9324a9)
  • xlsx: read a written-out bare time on the day a serial time reads on (010aca1)

Performance Improvements

  • analysis: ask the culture-free shape questions once per value, not once per culture (eba9e27)
  • analysis: count cell kinds in an array, not a dictionary (2b06499)
  • analysis: keep distinct-value hashes in a flat open-addressing set (c8eb8f6)
  • analysis: read a number once for cultures that write numbers alike (94fd7a8)
  • csv: make a field that is one run of the buffer straight from the buffer (d526580)
  • csv: take runs of ordinary text inside quotes as one span too (64d527b)
  • csv: take runs of ordinary text outside quotes as one span, found by a vectorised search (b1273a5)

v0.1.0

Choose a tag to compare

@github-actions github-actions released this 25 Sep 21:36
29ae631

0.1.0 (2026-09-25)

⚠ BREAKING CHANGES

  • one exception hierarchy with a code on every instance
  • one namespace for the workflow

Features

  • benchmarks: a synthetic fixture generator, so the published numbers can be reproduced (c913bd2)
  • let callers add their own value rules (4c0ec6c)
  • public ErrorCodes constants for every code the library reports (4bd9567)
  • report progress while analysing a file (0428a2a)

Bug Fixes

  • a successful MoveToSheet clears a fault from the sheet before (#14) (ef3589f)
  • a zoned timestamp is read as the clock time it states, on every server (e8b7883)
  • an empty shared string no longer hangs the xlsx reader (52c5fc2)
  • csv: read records joined by a pair of stray quotes as records, and count the repair (6832d78)
  • files in formats the library does not read are refused by name (7f5571f)
  • find workbook parts through the package relationships (8eb6890)
  • four value errors found against other readers' corpora (7ed3376)
  • HeaderRowIndex names a spreadsheet row, the numbering every report uses (4577245)
  • malformed parts and truncated worksheets are refused instead of leaking or shortening (d19aaf2)
  • options are validated up front, and invariant globalization degrades instead of failing (d7fff36)
  • read worksheets whose markup has elements with many attributes (3b3add5)
  • the import applies the profiler's number-grouping rule, and honours AllOrNothing (406f6f3)
  • the precheck judges a workbook's own numbers, dates and booleans against the field (dbf5855)
  • workbook row numbers only ever increase (b18cd0b)

Performance Improvements

  • read the shared string table with one chunk buffer, not one per entry (87104be)

Code Refactoring

  • one exception hierarchy with a code on every instance (34ab68f)
  • one namespace for the workflow (4dbd4a3)