csvx

package module
v0.1.15 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 6, 2026 License: MIT Imports: 23 Imported by: 0

README

CSVX Go Engine

csvx-go is a Go library — the programmable interface for CSVX (load/edit/calculate/write). It is specification-first: it must conform to CSVX behavior, but its internal architecture does not define the format. This repo is a library only — its CLI was split into csvx-cli, which depends on this repo as an ordinary Go module. See AGENTS.md and ../csvx-spec/AGENTS.md for why that split exists.

Internal

This project uses the CSVX Spec and Go engine

Current scope

  • CSVX ZIP package loading and writing (Open, Load, WritePackage)
  • Unpacked CSVX directory loading/packaging (OpenDirectory, PackageDirectory, ExtractPackage)
  • UTF-8 CSV sheet loading, RFC 4180-compatible
  • Optional .meta.json sheet metadata: formulas, cached values, per-cell styles, validation
  • Style generated from ../csvx-spec/schemas/styles.schema.json (see internal/schema/), not hand-typed — see AGENTS.md for why that matters
  • XLSX→CSVX import and unmodified-source recovery (Convert)
  • Duplicate and unsafe ZIP entry rejection
  • Basic structural validation (Validate)

Not yet implemented: formula parsing/recalculation, general CSVX→XLSX export of arbitrary/edited content (only unmodified-source recovery exists today), full schema-conformance validation (that lives in ../csvx-spec/validator for now). See handoff.md for current known limitations.

Development rule

Each capability follows this sequence:

Specify → create conformance fixtures → implement → run tests

The specification repository is the authority: ../csvx-spec/.

Usage

workbook, err := csvx.Open("report.csvx")
if err != nil {
    return err
}
fmt.Println(workbook.Sheets[0].Records)

CSV is the canonical sheet data layer. Metadata that CSV cannot represent is stored in the matching .meta.json sidecar.

To exercise this library from the command line, use csvx-cli.

Development

go build ./...                              # build
go vet ./...                                # static analysis
go test ./...                               # run all tests
go test -race ./...                         # with the race detector
go test -run TestLoadCSVBackedWorkbook ./... # a specific test
gofmt -w .                                   # format before committing
go mod tidy                                  # after changing imports — review the diff
Pre-push checks (local, since GitHub Actions minutes are limited)

scripts/check.sh runs the same checks CI would (gofmt, go vet, go build, go test). Run it any time:

./scripts/check.sh

A git hook runs it automatically before every push, blocking the push if it fails. Enable it once per clone (this is local git config, not something that comes from cloning the repo):

git config core.hooksPath .githooks

Skip in a genuine emergency with git push --no-verify — prefer fixing the failure instead. See ../csvx-spec/AGENTS.md section 6 for why this exists: it's the interim stand-in for real CI.

Development workflow

  1. Update the relevant specification in ../csvx-spec/.
  2. Add or update a conformance fixture.
  3. Implement the behavior in this library.
  4. Run ./scripts/check.sh (or let the pre-push hook do it).
  5. Document any intentionally unsupported behavior in handoff.md.
  6. Confirm that CSV data and metadata sidecars remain round-trip safe.

Do not treat engine behavior as a specification change without updating the specification repository.

Documentation

Overview

Package csvx provides a specification-first reader and writer for CSVX workbooks.

Index

Constants

View Source
const HeaderRow = -1

HeaderRow is the record index of the CSV header row (spec row 1).

Variables

This section is empty.

Functions

func CanonicalCellText added in v0.1.12

func CanonicalCellText(v Value) string

CanonicalCellText converts a value back to the raw text the sheet CSV stores.

func ChangeCase added in v0.1.10

func ChangeCase(text string, mode TextCaseMode, declaredType, formula string, header bool) string

ChangeCase returns the converted text, or text unchanged when the cell is not eligible. Mapping is per code point; a code point whose mapping is not exactly one code point is left unchanged. Mirrors csvx-ts's changeCase.

func ColumnWidthToPixels added in v0.1.2

func ColumnWidthToPixels(width float64) int

ColumnWidthToPixels converts an XLSX character-width unit (Column.width) to CSS pixels.

func Convert

func Convert(input, output string) error

Convert imports or exports a workbook based on the input and output extensions.

func CoordinateFor added in v0.1.12

func CoordinateFor(columnIndex, rowIndex int) string

CoordinateFor returns the A1 coordinate of a cell, e.g. CoordinateFor(0, HeaderRow) is "A1".

func ExtractPackage

func ExtractPackage(filename, directory string) error

ExtractPackage extracts a CSVX ZIP package into an unpacked directory.

func FormatSheetName added in v0.1.12

func FormatSheetName(name string) string

FormatSheetName formats a sheet name for use before `!`, quoting it unless it is a bare identifier.

func FormatValue added in v0.1.1

func FormatValue(value Value, numberFormat string) string

FormatValue renders a Value for display using an Excel-style numberFormat code, falling back to the plain value string when the value isn't numeric or the pattern isn't one of the supported shapes. Never mutates or reinterprets value — this is display text only. Mirrors csvx-ts's formatValue exactly; both engines must agree on every case in format_test.go.

func ImportCSV added in v0.1.5

func ImportCSV(data []byte, options CSVImportOptions) (*Workbook, []ImportWarning, error)

ImportCSV converts plain CSV bytes into a single-sheet workbook per spec §11.1. The workbook is in memory; write it with WritePackage.

func ImportCSVFile added in v0.1.5

func ImportCSVFile(filename string, options CSVImportOptions) (*Workbook, []ImportWarning, error)

ImportCSVFile reads a CSV file and imports it; an empty options.Name defaults to the file stem.

func IndicesForCoordinate added in v0.1.12

func IndicesForCoordinate(coordinate string) (column, row int, ok bool)

IndicesForCoordinate splits "AB12" into a zero-based column and record row index ("A1" has row HeaderRow). ok is false for an unparseable coordinate.

func IsCaseEligible added in v0.1.10

func IsCaseEligible(text, declaredType, formula string, header bool) bool

IsCaseEligible reports whether a cell's text may be case-converted: no formula, and it resolves to a string; a header cell (header true) is always a string. declaredType is the cell's resolved type ("" when nothing declares one).

func PackageDirectory

func PackageDirectory(directory, output string) error

PackageDirectory writes an unpacked CSVX package directory as a ZIP .csvx file.

func PixelsToColumnWidth added in v0.1.2

func PixelsToColumnWidth(pixels float64) float64

PixelsToColumnWidth converts CSS pixels back to an XLSX character-width unit — the inverse of ColumnWidthToPixels. Rounded to 2 decimal places, matching csvx-ts.

func PixelsToRowHeight added in v0.1.2

func PixelsToRowHeight(pixels float64) float64

PixelsToRowHeight converts CSS pixels back to points — the inverse of RowHeightToPixels.

func RawCellText added in v0.1.12

func RawCellText(sheet *Sheet, row, column int) string

RawCellText is a cell's raw text. For the header row that is the column name, which may be empty.

func RecalculateCells added in v0.1.12

func RecalculateCells(cells CellMap, options RecalculateOptions) map[string]Value

RecalculateCells recalculates every formula cell in a single-sheet coordinate map in dependency order and returns a result for each formula cell. Cells in a circular dependency all resolve to CYCLE.

func RecalculateSheets added in v0.1.12

func RecalculateSheets(sheets map[string]CellMap, external func(name string) CellMap, namedRanges []NamedRange) map[string]map[string]Value

RecalculateSheets recalculates every formula cell across a set of named sheets in dependency order (spec/10-calculation.md). The graph has an edge for every cell a formula reads — each cell inside a range, and cells on other sheets — so a reference to another sheet's formula cell sees its calculated value, and a cycle that crosses sheets is CYCLE in every cell on it. A reference to a sheet that is not in sheets (and not supplied by external) is REF. A declared name contributes the edges of its refersTo. It returns results only for cells that had a formula, keyed by sheet name and then coordinate.

func RewriteFormulaForAxisEdit added in v0.1.12

func RewriteFormulaForAxisEdit(formula, ownSheet, targetSheet string, edit AxisEdit) string

RewriteFormulaForAxisEdit rewrites a formula for a row or column insert/delete on targetSheet. ownSheet is the name of the sheet the formula lives on, which is what its unqualified references target.

func RewriteFormulaForSheetChange added in v0.1.12

func RewriteFormulaForSheetChange(formula, oldName, newName string, deleted bool) string

RewriteFormulaForSheetChange rewrites sheet-qualified references when a sheet is renamed (newName set) or deleted (deleted true: every reference to it becomes #REF!).

func RowHeightToPixels added in v0.1.2

func RowHeightToPixels(points float64) int

RowHeightToPixels converts a row height in points (Sheet.rowHeights) to CSS pixels, at the standard 96 DPI / 72-points-per-inch ratio every renderer (and XLSX itself) assumes.

func RowIndexFor added in v0.1.12

func RowIndexFor(rowNumber int) int

RowIndexFor returns the record index for a spec row number; row 1 is HeaderRow.

func RowNumberFor added in v0.1.12

func RowNumberFor(rowIndex int) int

RowNumberFor returns the spec row number (1-based, header = 1) for a record index.

func TranslateFormula added in v0.1.12

func TranslateFormula(formula string, rows, columns int) string

TranslateFormula translates a formula copied from one cell to another (spec/15, paste with From): every reference's relative column and row move by columns and rows, and parts marked absolute with `$` stay. A reference that would leave the sheet becomes #REF! (a whole range if either end would).

func UsedRange added in v0.1.12

func UsedRange(sheet *Sheet, styles []Style) (rows, columns int)

UsedRange returns the rows and columns up to the last cell that prints something (spec/03-sheets.md, "Used range"); it is always at least 1 x 1.

func WritePackage

func WritePackage(workbook *Workbook, output string) error

WritePackage writes a workbook to a deterministic CSVX ZIP package.

func WritePackageTo added in v0.1.12

func WritePackageTo(workbook *Workbook, file io.Writer) error

WritePackageTo writes a workbook as a deterministic CSVX ZIP package to any writer, so a package can be produced in memory (see ValidateWorkbook) as well as on disk.

Types

type AxisEdit added in v0.1.12

type AxisEdit struct {
	Axis    string // "row" or "column"
	Map     func(index int) int
	Deleted map[int]bool
}

AxisEdit describes one axis of a structural edit. Rows are numbered 1-based (A1 row numbers, header = 1) and columns 0-based; Map and Deleted use whichever convention Axis names.

type CSVExportOptions added in v0.1.13

type CSVExportOptions struct {
	// Sheet is a sheet id or name; empty means the first sheet.
	Sheet string
	// NoHeader omits the header row (spec option header=false).
	NoHeader bool
	// Delimiter is the field delimiter; 0 means ','.
	Delimiter rune
	// Formulas is "values" (the default, also for "") or "text".
	Formulas string
	// Display writes numbers as their number format displays them.
	Display bool
}

CSVExportOptions are the options of 11.2. The zero value is the spec default except NoHeader, which is inverted so the zero value is correct.

type CSVImportOptions added in v0.1.5

type CSVImportOptions struct {
	// Delimiter is the field delimiter; 0 means ','.
	Delimiter rune
	// NoHeader means the first record is data, not a header (spec option header=false).
	NoHeader bool
	// Infer declares column types from the data.
	Infer bool
	// Name is the sheet name; empty means "Sheet 1".
	Name string
}

CSVImportOptions are the options of csvx-spec/spec/11-import-export.md §11.1. The zero value is the spec default except Header, which is inverted (NoHeader) so the zero value is correct.

type CSVSyntaxError added in v0.1.5

type CSVSyntaxError struct {
	Line int
	Err  error
}

CSVSyntaxError reports malformed CSV with the 1-based line of the fault.

func (*CSVSyntaxError) Error added in v0.1.5

func (e *CSVSyntaxError) Error() string

func (*CSVSyntaxError) Unwrap added in v0.1.5

func (e *CSVSyntaxError) Unwrap() error

type Calculation

type Calculation struct {
	Mode      string `json:"mode,omitempty"`
	Iteration bool   `json:"iteration,omitempty"`
}

Calculation contains workbook calculation settings.

type CellMap added in v0.1.12

type CellMap map[string]FormulaCellInput

CellMap maps A1 coordinates to cell inputs.

func BuildCellMap added in v0.1.12

func BuildCellMap(sheet *Sheet, styles []Style) CellMap

BuildCellMap builds the flat coordinate -> {formula | value} map RecalculateCells expects for one sheet. Every cell gets an entry so a formula can read a plain cell, including a header cell.

type CellMetadata

type CellMetadata struct {
	Type       string          `json:"type,omitempty"`
	Formula    string          `json:"formula,omitempty"`
	Cached     *Value          `json:"cached,omitempty"`
	Style      string          `json:"style,omitempty"`
	Validation json.RawMessage `json:"validation,omitempty"`
}

CellMetadata contains behavior that cannot be represented in CSV.

func NextCellMetadata added in v0.1.1

func NextCellMetadata(existing CellMetadata, formula string) (CellMetadata, bool)

NextCellMetadata computes the next cell metadata after an edit overwrites a cell's content, per spec/05-cell-values.md: Type, Formula, and Cached describe a cell's *content* and must never survive past what they described, while Style and Validation describe the cell itself and are untouched. Consumer apps must call this rather than deciding for themselves which fields survive an edit (AGENTS.md rule 5.2 — no second opinion about what a CSVX value/type means). Pass a non-empty formula when the new content is a formula (starts with "="); pass "" for a literal edit. The second return value is false when nothing is left worth keeping (no metadata entry needed at all).

Note: CellMetadata in this engine is a closed struct (Type/Formula/Cached/Style/Validation only) rather than an open map, so unlike csvx-ts's nextCellMetadata this cannot yet preserve a field neither engine recognizes — that's an existing gap in this type (see its own doc comment), not one this function introduces.

type CellRef added in v0.1.12

type CellRef struct {
	Sheet  string
	HasSht bool
	Column string
	Row    int
}

CellRef is a parsed cell reference. Row is zero-based (A1 is Row 0); Column is the upper-cased column letters.

type Column

type Column struct {
	ID    string  `json:"id"`
	Name  string  `json:"name"`
	Type  string  `json:"type,omitempty"`
	Width float64 `json:"width,omitempty"`
}

Column describes a CSV column and its optional CSVX type.

type Diagnostic

type Diagnostic struct {
	Code     string `json:"code"`
	Path     string `json:"path,omitempty"`
	Message  string `json:"message"`
	Severity string `json:"severity"`
}

Diagnostic describes a validation error or warning at a package resource.

type EditOptions added in v0.1.12

type EditOptions struct {
	SkipRecalculate bool
	// From is used by Paste only: the coordinate the rows were copied from. When set, formula
	// texts are translated by the offset from From to the paste anchor (spec/15).
	From string
}

EditOptions tunes an edit operation. The zero value recalculates afterwards.

type ExportWarning added in v0.1.13

type ExportWarning struct {
	Feature  string `json:"feature"`
	Location string `json:"location"`
	Message  string `json:"message"`
}

ExportWarning is something a CSV export leaves out, with a location and reason.

func ExportCSV added in v0.1.13

func ExportCSV(workbook *Workbook, options CSVExportOptions) (string, []ExportWarning, error)

ExportCSV writes one sheet of a workbook as CSV text and reports what CSV cannot carry.

type FormulaCellInput added in v0.1.12

type FormulaCellInput struct {
	Formula string
	Value   Value
}

FormulaCellInput is one cell handed to RecalculateCells: a formula to evaluate or a plain value.

type FormulaNode added in v0.1.12

type FormulaNode struct {
	Kind     NodeKind
	Text     string // NodeNumber (literal text), NodeString, NodeCall (upper-cased name), NodeName (as written)
	Bool     bool
	Ref      CellRef      // NodeReference
	Start    *FormulaNode // NodeRange endpoints (NodeReference)
	End      *FormulaNode
	Args     []*FormulaNode // NodeCall
	Operator string         // NodeUnary, NodeBinary
	Operand  *FormulaNode   // NodeUnary, NodePercent
	Left     *FormulaNode   // NodeBinary
	Right    *FormulaNode
}

FormulaNode is a parsed formula expression. Which fields are set depends on Kind.

func ParseFormula added in v0.1.12

func ParseFormula(source string) (*FormulaNode, error)

ParseFormula parses a formula string (including the leading "=") into an AST. It returns a *FormulaParseError for invalid syntax, trailing tokens, or invalid references — spec/06-formulas.md requires parsing to reject these rather than guess.

type FormulaParseError added in v0.1.12

type FormulaParseError struct{ Message string }

FormulaParseError reports invalid formula syntax.

func (*FormulaParseError) Error added in v0.1.12

func (e *FormulaParseError) Error() string

type ImportWarning added in v0.1.5

type ImportWarning struct {
	Location string `json:"location"`
	Reason   string `json:"reason"`
}

ImportWarning is a lossy or adjusted step during import, with a location and reason.

type InvalidEditError added in v0.1.12

type InvalidEditError struct{ Message string }

InvalidEditError reports an operation the spec says is invalid.

func (*InvalidEditError) Error added in v0.1.12

func (e *InvalidEditError) Error() string

type InvalidNamedRangeError added in v0.1.12

type InvalidNamedRangeError struct{ Diagnostics []NamedRangeDiagnostic }

InvalidNamedRangeError is returned when a package declares invalid names.

func (*InvalidNamedRangeError) Error added in v0.1.12

func (e *InvalidNamedRangeError) Error() string

type Manifest

type Manifest struct {
	Format   string   `json:"format"`
	Version  string   `json:"version"`
	Workbook string   `json:"workbook"`
	Files    []string `json:"files"`
}

Manifest identifies a CSVX package and its resources.

type NamedRange added in v0.1.12

NamedRange is a workbook-scoped name (spec/02-workbook.md, Named ranges). Like Style, it is a defined type over the generated struct so unknown properties round-trip (rule 3.6).

func (NamedRange) MarshalJSON added in v0.1.12

func (n NamedRange) MarshalJSON() ([]byte, error)

MarshalJSON writes the typed fields plus preserved unknown properties, without the generated AdditionalProperties bucket key itself.

func (*NamedRange) UnmarshalJSON added in v0.1.12

func (n *NamedRange) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes through the generated type so the name pattern is enforced and unknown properties land in AdditionalProperties.

type NamedRangeDiagnostic added in v0.1.12

type NamedRangeDiagnostic struct {
	Code    string
	Name    string
	Message string
}

NamedRangeDiagnostic is one violation of the named-range rules.

func ValidateNamedRanges added in v0.1.12

func ValidateNamedRanges(namedRanges []NamedRange) []NamedRangeDiagnostic

ValidateNamedRanges checks declared names against the rules in spec/02-workbook.md. It returns one diagnostic per offending name; an empty result means valid.

type NodeKind added in v0.1.12

type NodeKind int

NodeKind identifies a FormulaNode variant.

const (
	NodeNumber NodeKind = iota
	NodeString
	NodeBoolean
	NodeRefError
	NodeName
	NodeReference
	NodeRange
	NodeCall
	NodeUnary
	NodePercent
	NodeBinary
)

type Page added in v0.1.12

type Page struct {
	Number  int      `json:"number"`
	Rows    []int    `json:"rows"`    // A1 row numbers shown, repeated rows first
	Columns []string `json:"columns"` // column letters shown, repeated columns first
}

Page is one printed page.

type Pagination added in v0.1.12

type Pagination struct {
	PrintableWidth  float64 // unscaled CSS pixels inside the margins
	PrintableHeight float64
	Scale           float64
	Area            string // the printed area as an A1 range, or "" when nothing is left to print
	Pages           []Page
}

Pagination is the layout of a sheet's print area into pages.

func Paginate added in v0.1.12

func Paginate(sheet *Sheet, styles []Style) Pagination

Paginate lays a sheet's print area out as pages, exactly as spec/03-sheets.md ("Pagination") describes.

type PrintSettings added in v0.1.3

type PrintSettings schema.Print

PrintSettings is a sheet's print and pagination settings (spec/03-sheets.md, "Print settings"). Its fields are generated from csvx-spec's sheet-metadata.schema.json. Properties the schema does not define are kept in AdditionalProperties and written back out, as the spec requires.

func (PrintSettings) MarshalJSON added in v0.1.3

func (p PrintSettings) MarshalJSON() ([]byte, error)

MarshalJSON writes the typed fields plus any preserved unknown properties, without the generated AdditionalProperties bucket key itself.

func (*PrintSettings) UnmarshalJSON added in v0.1.3

func (p *PrintSettings) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes through the generated type so enums and ranges are validated and unknown properties land in AdditionalProperties.

type RecalculateOptions added in v0.1.12

type RecalculateOptions struct {
	// ResolveSheet returns the cell map of a sheet named by a `Sheet!A1` reference, or nil.
	ResolveSheet func(name string) CellMap
}

RecalculateOptions configures RecalculateCells.

type ReferenceRequest added in v0.1.12

type ReferenceRequest struct {
	Sheet    string
	HasSheet bool
	Column   string
	Row      int
}

ReferenceRequest is a cell a formula reads. Row is zero-based.

type ReferenceResolver added in v0.1.12

type ReferenceResolver func(ReferenceRequest) Value

ReferenceResolver returns the current value of a referenced cell.

type Sheet

type Sheet struct {
	ID           string                     `json:"id"`
	Name         string                     `json:"name"`
	Path         string                     `json:"path"`
	MetadataPath string                     `json:"metadata,omitempty"`
	Columns      []Column                   `json:"columns"`
	Records      [][]string                 `json:"records"`
	RowHeights   map[int]float64            `json:"rowHeights,omitempty"`
	Print        *PrintSettings             `json:"print,omitempty"`
	Cells        map[string]CellMetadata    `json:"cells,omitempty"`
	Extra        map[string]json.RawMessage `json:"-"`
}

Sheet is a CSV-backed worksheet. Records excludes the CSV header row.

type SheetEntry

type SheetEntry struct {
	ID       string `json:"id"`
	Name     string `json:"name"`
	Path     string `json:"path"`
	Metadata string `json:"metadata,omitempty"`
}

SheetEntry locates a sheet's CSV and optional metadata sidecar in a package.

type SourceMetadata

type SourceMetadata struct {
	Format     string            `json:"format"`
	Filename   string            `json:"filename"`
	SHA256     string            `json:"sha256"`
	Authority  string            `json:"authority"`
	ImportedAt string            `json:"importedAt"`
	Importer   string            `json:"importer"`
	Features   XLSXFeatureCounts `json:"features,omitempty"`
	Warnings   []XLSXDiagnostic  `json:"warnings,omitempty"`
}

SourceMetadata describes an embedded external workbook preserved for interoperability.

type Style

Style is a single style record. Its field shape is generated from csvx-spec's styles.schema.json (see internal/schema/generated.go) rather than hand-typed, so it cannot silently drift from the schema the way the previous hand-written map[string]map[string]any representation did.

This is a defined type over the generated struct, not a plain alias, solely so MarshalJSON below can omit the generated AdditionalProperties bucket field until this engine implements real additionalProperties round-tripping on both read and write (styles.json is not read back in anywhere yet, so nothing currently depends on inheriting the generated UnmarshalJSON here).

func (Style) MarshalJSON

func (s Style) MarshalJSON() ([]byte, error)

MarshalJSON writes the typed fields plus any preserved unknown properties (at the style level and inside border), without the generated AdditionalProperties bucket key itself.

func (*Style) UnmarshalJSON added in v0.1.12

func (s *Style) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes through the generated type so the id pattern is enforced and properties the schema does not define land in AdditionalProperties (rule 3.6: unknown fields round-trip).

type TextCaseMode added in v0.1.10

type TextCaseMode string

TextCaseMode selects a case conversion (csvx-spec/spec/05-cell-values.md, "Text case").

const (
	CaseUpper TextCaseMode = "upper"
	CaseLower TextCaseMode = "lower"
	CaseTitle TextCaseMode = "title"
)

type ValidationResult

type ValidationResult struct {
	Valid    bool         `json:"valid"`
	Errors   []Diagnostic `json:"errors"`
	Warnings []Diagnostic `json:"warnings"`
}

ValidationResult contains machine-readable package validation output.

func Validate

func Validate(filename string) ValidationResult

Validate checks a CSVX ZIP file or unpacked CSVX directory.

func ValidateWorkbook added in v0.1.12

func ValidateWorkbook(workbook *Workbook) ValidationResult

ValidateWorkbook validates a workbook that exists only in memory — for example one that has been edited but not yet saved — by serializing it exactly as WritePackage would and loading the result back, so what is checked is what would be written. Like Validate, this is a structural check (the package loads, resources decode, named ranges are valid); JSON-Schema conformance has one home, csvx-spec/validator (csvx-spec/AGENTS.md rule 3.3), which a host can run on the saved package.

type Value

type Value struct {
	Type    string `json:"type"`
	Value   any    `json:"value,omitempty"`
	Code    string `json:"code,omitempty"`
	Message string `json:"message,omitempty"`
}

Value is a typed CSVX value used by formulas, caches, and diagnostics.

func EvaluateFormula added in v0.1.12

func EvaluateFormula(formula string, resolve ReferenceResolver, namedRanges []NamedRange) Value

EvaluateFormula evaluates a formula string (including the leading "=") against a reference resolver. A parse error surfaces as a NAME error rather than a Go error, since a formula cell with invalid syntax is still a valid cell state a UI must be able to render.

func ParseFormattedLiteral added in v0.1.1

func ParseFormattedLiteral(text string, numberFormat string) (Value, bool)

ParseFormattedLiteral is the inverse of FormatValue: it attempts to parse typed literal text back into a numeric Value using a cell's own numberFormat, per spec/08-styles.md's symmetric allowance — e.g. "$7.00" against `"$"#,##0.00` becomes decimal "7.00" instead of falling through to string just because it has a currency symbol. Scoped strictly to the same documented format subset FormatValue supports; this is not general multi-locale currency parsing (see the package comment for why). Returns (Value{}, false) for text that doesn't match the format's own affix/grouping shape, or when there is no numberFormat at all — the caller falls through to its own generic literal rules either way. Mirrors csvx-ts's parseFormattedLiteral.

func ResolveCellValue added in v0.1.1

func ResolveCellValue(raw string, declaredType string, numberFormat string) Value

ResolveCellValue resolves a sheet CSV cell's raw text to a typed Value, per csvx-spec/spec/05-cell-values.md and 03-sheets.md: "Column types provide defaults and validation hints; an individual cell MAY override a column type." This is the one place that decision gets made — consumer apps must call this rather than sniffing "looks like a number" themselves (csvx-spec/AGENTS.md rule 1). declaredType is the resolved cell/column type (a cell's own Type override wins over its column's); pass "" when nothing declares a type at all.

When nothing declares a type (true for any hand-authored or freshly-edited CSVX, as opposed to an exhaustively cell-annotated XLSX import), numberFormat (the cell's resolved style numberFormat, if any) is tried first, per spec/08-styles.md's symmetric parsing allowance — "$7.00" against a `"$"#,##0.00` numberFormat resolves to decimal "7.00" rather than falling through to string just because it looks like currency text (see ParseFormattedLiteral for the documented, bounded subset this covers). Failing that, this falls back to the same narrow, well-established literal-shape inference every CSV-consuming spreadsheet tool uses (blank/boolean/integer/decimal by shape, otherwise string) rather than defaulting everything untyped to "string" and silently breaking formula arithmetic over it. A declared type (including an explicit "string") always wins and is never second-guessed, and never consults numberFormat. Mirrors csvx-ts's resolveCellValue — see that implementation for the TypeScript engine's identical contract.

type Workbook

type Workbook struct {
	ID          string          `json:"id"`
	Version     string          `json:"version"`
	Sheets      []*Sheet        `json:"sheets"`
	NamedRanges []NamedRange    `json:"namedRanges,omitempty"`
	Calculation Calculation     `json:"calculation,omitempty"`
	Source      *SourceMetadata `json:"source,omitempty"`
	Styles      []Style         `json:"styles,omitempty"`
	SourceBytes []byte          `json:"-"`
	// contains filtered or unexported fields
}

Workbook is the canonical in-memory representation of a CSVX workbook.

func AddSheet added in v0.1.12

func AddSheet(workbook *Workbook, options EditOptions) *Workbook

AddSheet appends an empty sheet: one column with the empty name and no data rows.

func ApplyStyle added in v0.1.12

func ApplyStyle(workbook *Workbook, sheet string, coordinates []string, patch map[string]any, options EditOptions) (*Workbook, error)

ApplyStyle merges patch into each listed cell's style, reusing an identical existing style or adding one (s<N>). Existing styles are never modified.

func ClearStyle added in v0.1.12

func ClearStyle(workbook *Workbook, sheet string, coordinates []string, options EditOptions) (*Workbook, error)

ClearStyle removes the style reference from each listed cell; styles are untouched.

func DeleteColumns added in v0.1.12

func DeleteColumns(workbook *Workbook, sheet string, columns []string, options EditOptions) (*Workbook, error)

DeleteColumns deletes the columns with the given letters in one pass; a sheet keeps at least one column.

func DeleteRows added in v0.1.12

func DeleteRows(workbook *Workbook, sheet string, rows []int, options EditOptions) (*Workbook, error)

DeleteRows deletes the given rows (A1 row numbers, each at least 2) in one pass.

func DeleteSheet added in v0.1.12

func DeleteSheet(workbook *Workbook, sheet string, options EditOptions) (*Workbook, error)

DeleteSheet deletes a sheet; references to it become #REF!. A workbook keeps at least one sheet.

func InsertColumns added in v0.1.12

func InsertColumns(workbook *Workbook, sheet, at string, count int, options EditOptions) (*Workbook, error)

InsertColumns inserts count blank columns before the column with letter at. The new columns have the empty name (spec/03-sheets.md, spec/15).

func InsertRows added in v0.1.12

func InsertRows(workbook *Workbook, sheet string, at, count int, options EditOptions) (*Workbook, error)

InsertRows inserts count blank rows before row number at (an A1 row number, at least 2).

func Load

func Load(reader io.ReaderAt, size int64) (*Workbook, error)

Load reads a CSVX ZIP package from an io.ReaderAt with the supplied size.

func Open

func Open(filename string) (*Workbook, error)

Open reads a CSVX ZIP package from disk.

func OpenDirectory

func OpenDirectory(directory string) (*Workbook, error)

OpenDirectory reads an unpacked CSVX package directory.

func Paste added in v0.1.12

func Paste(workbook *Workbook, sheet, anchor string, rows [][]string, options EditOptions) (*Workbook, error)

Paste applies a rectangle of texts, top-left at anchor, as one SetCell each. It is atomic: if any element is invalid, nothing is applied. Formula text is stored verbatim unless options.From is set, in which case it is translated (spec/15).

func RecalculateWorkbook added in v0.1.12

func RecalculateWorkbook(workbook *Workbook) *Workbook

RecalculateWorkbook recalculates every formula cell in every sheet and returns a new workbook; the input is not modified. Cross-sheet references resolve against each other sheet's cell map by name.

func RenameSheet added in v0.1.12

func RenameSheet(workbook *Workbook, sheet, name string, options EditOptions) (*Workbook, error)

RenameSheet renames a sheet and rewrites every sheet-qualified reference to it.

func SetCell added in v0.1.12

func SetCell(workbook *Workbook, sheet, coordinate, text string, options EditOptions) (*Workbook, error)

SetCell replaces a cell's content with what the user typed (a formula if it starts with "=").

func SetPrint added in v0.1.12

func SetPrint(workbook *Workbook, sheet string, patch map[string]any, options EditOptions) (*Workbook, error)

SetPrint merges patch into the sheet's print settings: a key set to nil is removed, unmentioned and unknown keys are kept, and an emptied object is removed.

type WorkbookDocument

type WorkbookDocument struct {
	ID          string          `json:"id"`
	Version     string          `json:"version"`
	Sheets      []SheetEntry    `json:"sheets"`
	NamedRanges []NamedRange    `json:"namedRanges,omitempty"`
	Calculation Calculation     `json:"calculation,omitempty"`
	Source      *SourceMetadata `json:"source,omitempty"`
	Styles      string          `json:"styles,omitempty"`
}

WorkbookDocument is the serialized workbook resource.

type XLSXDiagnostic

type XLSXDiagnostic struct {
	Severity string `json:"severity"`
	Feature  string `json:"feature"`
	Path     string `json:"path,omitempty"`
	Message  string `json:"message"`
}

XLSXDiagnostic records an interoperability limitation or observation.

func ExportXLSX added in v0.1.12

func ExportXLSX(workbook *Workbook, output string) ([]XLSXDiagnostic, error)

ExportXLSX writes a workbook to an XLSX file and returns the warnings for everything that could not be represented exactly.

func ExportXLSXTo added in v0.1.12

func ExportXLSXTo(workbook *Workbook, out io.Writer) ([]XLSXDiagnostic, error)

ExportXLSXTo writes a workbook as XLSX to any writer; see ExportXLSX.

type XLSXFeatureCounts

type XLSXFeatureCounts struct {
	SharedStrings int `json:"sharedStrings"`
	Styles        int `json:"styles"`
	NumberFormats int `json:"numberFormats"`
	Drawings      int `json:"drawings"`
	Charts        int `json:"charts"`
	Images        int `json:"images"`
	Comments      int `json:"comments"`
	Persons       int `json:"persons"`
	Macros        int `json:"macros"`
	Relationships int `json:"relationships"`
}

XLSXFeatureCounts summarizes workbook features relevant to CSVX interoperability.

type XLSXInspection

type XLSXInspection struct {
	Format    string            `json:"format"`
	Filename  string            `json:"filename"`
	SHA256    string            `json:"sha256"`
	Sheets    []XLSXSheet       `json:"sheets"`
	Features  XLSXFeatureCounts `json:"features"`
	Resources []string          `json:"resources"`
	Warnings  []XLSXDiagnostic  `json:"warnings"`
}

XLSXInspection describes the portable features and package resources detected in an XLSX file.

func InspectXLSX

func InspectXLSX(filename string) (*XLSXInspection, error)

InspectXLSX reads an XLSX package without executing macros, links, or external resources.

type XLSXSheet

type XLSXSheet struct {
	Name          string `json:"name"`
	Path          string `json:"path"`
	Cells         int    `json:"cells"`
	Formulas      int    `json:"formulas"`
	CachedValues  int    `json:"cachedValues"`
	StyledCells   int    `json:"styledCells"`
	SharedStrings int    `json:"sharedStrings"`
}

XLSXSheet describes one worksheet and its understood cell features.

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL