tidyvcf 0.7.3

command-line tool to convert VCF files to tab/comma separated tables
Documentation
use std::{error::Error, io::BufRead};

use noodles::vcf::{header, Header};

pub fn read_header_lenient(mut reader: impl BufRead) -> Result<Header, Box<dyn Error>> {
    let mut header = String::new();
    let mut buffer = String::new();

    while !header.contains("#CHROM\t") {
        reader.read_line(&mut buffer)?;
        if header_line_needed(&buffer) {
            header.push_str(&buffer);
        }
        buffer.clear();
    }

    let header = ensure_spec_compliance(&mut header);

    let parser = header::Parser::builder().build();

    Ok(parser.parse(&header)?)
}

fn header_line_needed(line: &str) -> bool {
    line.starts_with("##contig")
        || line.starts_with("##fileformat")
        || line.starts_with("##INFO")
        || line.starts_with("##FILTER")
        || line.starts_with("##FORMAT")
        || line.starts_with("#CHROM\t")
}

fn ensure_spec_compliance(header: &mut str) -> String {
    // Octopus issues
    let newheader = header
        .replace(
            "##FORMAT=<ID=GT,Number=1,Type=Float",
            "##FORMAT=<ID=GT,Number=1,Type=String",
        )
        .replace(
            "##INFO=<ID=MQ,Number=1,Type=Integer",
            "##INFO=<ID=MQ,Number=1,Type=Float",
        );
    // VarScan issue
    if header.contains("##fileformat=VCFv4.3") && header.contains("##FORMAT=<ID=AD,Number=1") {
        return newheader.replace("##fileformat=VCFv4.3", "##fileformat=VCFv4.2");
    }
    newheader
}