@gmod/vcf
Version:
High performance streaming Variant Call Format (VCF) parser in pure JavaScript
120 lines • 4.51 kB
JavaScript
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