moonbit-vcfkit

Native MoonBit toolkit for parsing, filtering, transforming, and inspecting VCF text data.

vcf
genomics
bioinformatics
variant
cli
moon add chgttyyr/moonbit-vcfkit@0.1.0
Download zip
Author
Version
0.1.0
License
Apache-2.0
Last updated
19 days ago
Downloads
4
README

#MoonBit VCF Kit

moonbit-vcfkit is a native MoonBit toolkit for Variant Call Format text data. It focuses on the parts that are useful before a project needs the full htslib stack: header inspection, typed record parsing, compact filtering, small transformations, deterministic writing, and testable command behavior.

The package is written in MoonBit and uses synthetic fixtures only. It is intended for developer tools, teaching fixtures, lightweight data checks, and MoonBit ecosystem experiments. It is not a clinical validation tool.

#What Works

  • Parse VCF 4.x-style header lines, including INFO, FORMAT, FILTER, contig, fileformat, and generic metadata.
  • Parse records into typed INFO and FORMAT values using header descriptors.
  • Filter records with expressions such as qual >= 30, has info.SOMATIC, and format.TUMOR.DP >= 20.
  • Split multi-allelic records into one alternate allele per output record.
  • Apply basic allele trimming normalization for simple single-alt records.
  • Serialize documents back to stable VCF text.
  • Summarize contigs, filters, INFO keys, sample count, multi-allelic records, and variant classes.
  • Run golden tests across wasm, wasm-gc, JavaScript, and native targets.
  • Provide a small CLI harness package plus cmd/vcfkit entrypoint.

#Package Map

  • Root package: domain types, header/record parser, writer, transforms, stats.
  • filter: expression parser and evaluator.
  • cli: pure command dispatcher over VCF text.
  • cmd/vcfkit: executable entrypoint; reads demo input from VCFKIT_INPUT.
  • internal/text: small scanner helpers.
  • internal/normalize: allele trimming helper.

#Quick Check

moon version --all moon check --target all --deny-warn moon test --target all --deny-warn moon fmt --check moon info

The repository also includes:

pwsh scripts/audit.ps1

#CLI Demo

The executable path is intentionally thin. For shell demos, pass VCF text through VCFKIT_INPUT:

moon run cmd/vcfkit -- help

Core command behavior is tested through cli.run_cli_text(argv, input), so applications can embed the same logic without depending on shell IO.

#Fixture Example

fixtures/basic.vcf contains three synthetic records covering a SNV, a multi-allelic insertion case, a deletion, typed INFO values, and FORMAT sample values. Expected outputs live under fixtures/golden/.

#Current Boundaries

This version handles plain VCF text. It does not implement BCF, bgzip/tabix indexing, streaming decompression, external FASTA-backed left alignment, annotation databases, or clinical interpretation.

#Source Notes

The implementation is original MoonBit source. VCF behavior is informed by the public hts-specs VCF documents, and MoonBit CI follows the public moonbit-community/.github workflow template shape with stricter warning checks. See docs/sources.md and docs/self-audit.md.

#License

Apache-2.0.

#
ParseError

pub(all) suberror ParseError {
InvalidHeader(line~ : Int, column~ : Int, message~ : String)
InvalidRecord(line~ : Int, column~ : Int, field~ : String, message~ : String)
InvalidValue(line~ : Int, column~ : Int, field~ : String, value~ : String, message~ : String)
} derive(Eq,
Debug
)

#
Cardinality

pub(all) enum Cardinality {
Fixed(Int)
PerAlt
PerAllele
PerGenotype
Variable
Unknown(String)
} derive(Eq,
Debug
)

#
ContigDef

pub(all) struct ContigDef {
id : String
length : Int?
attributes : Array[(String, String)]
} derive(Eq,
Debug
)

#
FilterDef

pub(all) struct FilterDef {
id : String
description : String
attributes : Array[(String, String)]
} derive(Eq,
Debug
)

#
FormatDef

pub(all) struct FormatDef {
id : String
number : Cardinality
value_type : ValueType
description : String
attributes : Array[(String, String)]
} derive(Eq,
Debug
)

#
InfoDef

pub(all) struct InfoDef {
id : String
number : Cardinality
value_type : ValueType
description : String
attributes : Array[(String, String)]
} derive(Eq,
Debug
)

#
MetaLine

pub(all) enum MetaLine {
FileFormat(String)
Info(InfoDef)
Format(FormatDef)
Filter(FilterDef)
Contig(ContigDef)
Generic(key~ : String, value~ : String)
} derive(Eq,
Debug
)

#
SampleCall

pub(all) struct SampleCall {
name : String
values : Array[(String, VcfValue)]
} derive(Eq,
Debug
)

#
ValueType

pub(all) enum ValueType {
Integer
Float
Flag
Character
String
Unknown(String)
} derive(Eq,
Debug
)

#
VcfDocument

pub(all) struct VcfDocument {
header : VcfHeader
records : Array[VcfRecord]
} derive(Eq,
Debug
)

#
VcfHeader

pub(all) struct VcfHeader {
fileformat : String
meta : Array[MetaLine]
columns : Array[String]
samples : Array[String]
} derive(Eq,
Debug
)

#
VcfRecord

pub(all) struct VcfRecord {
chrom : String
pos : Int
ids : Array[String]
ref_allele : String
alt_alleles : Array[String]
qual : Double?
filters : Array[String]
info : Array[(String, VcfValue)]
format_keys : Array[String]
samples : Array[SampleCall]
} derive(Eq,
Debug
)

#
VcfStats

pub(all) struct VcfStats {
record_count : Int
contig_counts : Array[(String, Int)]
filter_counts : Array[(String, Int)]
info_counts : Array[(String, Int)]
variant_type_counts : Array[(String, Int)]
sample_count : Int
multiallelic_count : Int
} derive(Eq,
Debug
)

#
VcfValue

pub(all) enum VcfValue {
Missing
Flag
Integer(Int)
Float(Double)
String(String)
List(Array[VcfValue])
} derive(Eq,
Debug
)

#
format_document

fn format_document(document : VcfDocument) -> String

#
format_header

fn format_header(header : VcfHeader) -> String

#
format_record

fn format_record(record : VcfRecord) -> String

#
format_stats

fn format_stats(stats : VcfStats) -> String

#
normalize_basic

fn normalize_basic(record : VcfRecord) -> VcfRecord

#
parse_document

fn parse_document(text : String) -> VcfDocument raise ParseError

#
parse_header

fn parse_header(text : String) -> VcfHeader raise ParseError

#
parse_meta_line

fn parse_meta_line(line : String, line_number~ : Int) -> MetaLine raise ParseError

#
parse_record

fn parse_record(line : String, header~ : VcfHeader) -> VcfRecord raise ParseError

#
split_multi_allelic

fn split_multi_allelic(record : VcfRecord) -> Array[VcfRecord]

#
summarize

fn summarize(document : VcfDocument) -> VcfStats