[package]
name = "anomalyx-normalize"
version.workspace = true
edition.workspace = true
rust-version.workspace = true
license.workspace = true
repository.workspace = true
description = "anomalyx normalization: any input format -> the ax-core RecordSet"
keywords = ["csv", "parquet", "arrow", "normalization", "dataframe"]
categories = ["parsing", "encoding"]

[dependencies]
ax-core = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
thiserror = { workspace = true }
csv = "1"
# YAML manifests (Kubernetes / CI) are deserialized into a serde_json::Value and
# lowered through the same record path as JSON. Lightweight, pure-Rust, and
# deterministic (sorted keys), so it stays on in the text-only build too.
serde_yaml = "0.9"
# TOML configs. Parsed to a toml::Value, converted to a serde_json::Value, then
# lowered like JSON/YAML. INI is hand-rolled (no extra dep). Both feed the
# config-drift use case via struct.schema.
toml = "0.8"
# Syslog (RFC 3164 / 5424) wire messages. The dual-RFC field parsing (BSD vs ISO
# timestamps, structured data) is delegated to this permissive parser; we derive
# the numeric facility/severity ourselves from the <PRI> header. We pin a fixed
# year + UTC (chrono::Utc) when parsing so a year-less RFC 3164 timestamp stays
# deterministic — syslog_loose's default path reads the wall clock / local zone.
syslog_loose = "0.23"
chrono = "0.4"
# XML (scan reports like Nessus/OpenVAS, SOAP, configs). Read-only DOM; we flatten
# the most-repeated element group to rows. Lightweight, pure-Rust, deterministic.
roxmltree = "0.21"
# Polars/Arrow backbone for binary columnar formats (Parquet, Arrow IPC), behind
# the RecordSet boundary and the default-on `polars` feature. Text formats never
# touch it; `--no-default-features` yields a lean text-only normalizer.
polars = { version = "0.53", default-features = false, features = [
    "parquet",
    "ipc",
], optional = true }
# EVTX (Windows Event Log) is a binary format; delegated to the `evtx` crate,
# which decodes each record to a serde_json::Value that we flatten like the other
# JSON-shaped sources. Behind the default-on `evtx` feature, so the text-only
# `--no-default-features` build stays lean.
evtx = { version = "0.11", optional = true }
# PCAP / PCAPNG packet captures. `pcap-parser` decodes the container (both
# formats) into per-packet timestamp/length/data; `etherparse` decodes the
# Ethernet/IPv4/transport headers to src/dst/ports. Behind the default-on `pcap`
# feature, so the text-only build stays lean.
pcap-parser = { version = "0.17", optional = true }
etherparse = { version = "0.20", optional = true }
# Excel (.xlsx/.xls/.xlsb) and OpenDocument (.ods) spreadsheets. calamine reads
# all of them (pure Rust) and we lower the first sheet to a RecordSet. Behind the
# default-on `xlsx` feature (binary format), so the text-only build stays lean.
calamine = { version = "0.35", optional = true }
# SQLite database files. `bundled` compiles SQLite from source (self-contained,
# no system lib) with the deserialize API so we can open a DB from a byte buffer.
# Behind the default-on `sqlite` feature (binary format).
rusqlite = { version = "0.40", features = [
    "bundled",
    "serialize",
], optional = true }
# Avro and ORC, the data-lake siblings of Parquet. Avro via apache-avro (records
# flattened to columns); ORC via orc-rust into Arrow batches lowered to columns.
# Behind the default-on `datalake` feature (binary formats).
apache-avro = { version = "0.21", optional = true }
orc-rust = { version = "0.8", optional = true }
# Pinned to the arrow major that orc-rust depends on (so the RecordBatch types unify).
arrow = { version = "58", optional = true, default-features = false }
bytes = { version = "1", optional = true }

[features]
default = ["polars", "evtx", "pcap", "xlsx", "sqlite", "datalake"]
polars = ["dep:polars"]
evtx = ["dep:evtx"]
pcap = ["dep:pcap-parser", "dep:etherparse"]
xlsx = ["dep:calamine"]
sqlite = ["dep:rusqlite"]
datalake = ["dep:apache-avro", "dep:orc-rust", "dep:arrow", "dep:bytes"]

[dev-dependencies]
proptest = { workspace = true }
# Writes a tiny .xlsx in-memory for the xlsx parser's roundtrip test (no
# committed binary fixture).
rust_xlsxwriter = "0.95"
