UNPKG

@gmod/vcf

Version:

High performance streaming Variant Call Format (VCF) parser in pure JavaScript

120 lines 4.51 kB
import { parseGenotypesOnly } from "./parseGenotypesOnly.js"; import { parseInfo } from "./parseInfo.js"; import { processGenotypes } from "./processGenotypes.js"; export class Variant { CHROM; POS; ID; REF; ALT; QUAL; FILTER; INFO; FORMAT; formatMeta; rest; sampleNames; constructor(line, infoMeta, formatMeta, sampleNames, strict) { const lineLen = line.length; let currChar = 0; let tabCount = 0; while (currChar < lineLen && tabCount < 9) { if (line.charCodeAt(currChar) === 9) { tabCount += 1; } currChar += 1; } const splitPos = tabCount === 9 ? currChar - 1 : currChar; const fields = line.slice(0, splitPos).split('\t'); const rest = line.slice(splitPos + 1); const [CHROM, POS, ID, REF, ALT, QUAL, FILTER] = fields; const filter = FILTER === '.' ? undefined : FILTER?.split(';'); if (strict && !fields[7]) { throw new Error("no INFO field specified, must contain at least a '.' (turn off strict mode to allow)"); } this.CHROM = CHROM; this.POS = POS !== undefined ? +POS : 0; this.ID = ID === '.' ? undefined : ID?.split(';'); this.REF = REF; this.ALT = ALT === '.' ? undefined : ALT?.split(','); this.QUAL = QUAL === undefined || QUAL === '.' ? undefined : +QUAL; this.FILTER = filter?.length === 1 && filter[0] === 'PASS' ? 'PASS' : filter; this.INFO = fields[7] === undefined || fields[7] === '.' ? {} : parseInfo(fields[7], infoMeta); this.FORMAT = fields[8]; this.formatMeta = formatMeta; this.rest = rest; this.sampleNames = sampleNames; } SAMPLES() { const genotypes = {}; const format = this.FORMAT; if (format) { const rest = this.rest.split('\t'); const formatKeys = format.split(':'); const isNumberType = formatKeys.map(k => { const t = this.formatMeta[k]?.Type; return t === 'Integer' || t === 'Float'; }); const numKeys = formatKeys.length; const samplesLen = this.sampleNames.length; for (let i = 0; i < samplesLen; i++) { const sample = this.sampleNames[i] ?? ''; const sampleData = {}; const sampleStr = rest[i] ?? ''; const sampleStrLen = sampleStr.length; let colStart = 0; let colIdx = 0; for (let j = 0; j <= sampleStrLen; j++) { if (j === sampleStrLen || sampleStr[j] === ':') { const key = formatKeys[colIdx] ?? ''; const val = sampleStr.slice(colStart, j); if (val === '' || val === '.') { sampleData[key] = undefined; } else { const items = val.split(','); const itemsLen = items.length; const isNum = isNumberType[colIdx]; const result = []; for (let k = 0; k < itemsLen; k++) { const ent = items[k] ?? ''; result.push(ent === '.' ? undefined : isNum ? +ent : ent); } sampleData[key] = result; } colStart = j + 1; colIdx += 1; if (colIdx >= numKeys) { break; } } } genotypes[sample] = sampleData; } } return genotypes; } GENOTYPES() { return parseGenotypesOnly(this.FORMAT ?? '', this.rest, this.sampleNames); } processGenotypes(callback) { processGenotypes(this.FORMAT ?? '', this.rest, this.sampleNames.length, callback); } toJSON() { return { CHROM: this.CHROM, POS: this.POS, ID: this.ID, REF: this.REF, ALT: this.ALT, QUAL: this.QUAL, FILTER: this.FILTER, INFO: this.INFO, FORMAT: this.FORMAT, }; } } //# sourceMappingURL=Variant.js.map