UNPKG

@gmod/vcf

Version:

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

96 lines 3.25 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.processGenotypes = processGenotypes; /** * Process genotypes by calling a callback for each one, avoiding intermediate * object/string allocation. This is useful for operations like counting alleles * where you don't need to build the full genotypes object. * * @param format - The FORMAT field from the VCF line * @param prerest - The sample data portion of the VCF line (after FORMAT) * @param samplesLen - Number of samples * @param callback - Called for each genotype with (string, startIndex, endIndex) */ const TAB = 9; const COLON = 58; const G = 71; const T = 84; // Column index of the exact "GT" field among the colon-separated FORMAT // keys, or -1 if absent. Matches the field exactly so keys that merely // contain "GT" (e.g. GATK's PGT) are not mistaken for it. function gtColumnIndex(format) { let col = 0; let start = 0; const len = format.length; for (let j = 0; j <= len; j++) { if (j === len || format.charCodeAt(j) === COLON) { if (j - start === 2 && format.charCodeAt(start) === G && format.charCodeAt(start + 1) === T) { return col; } col++; start = j + 1; } } return -1; } function processGenotypes(format, prerest, samplesLen, callback) { const prerestLen = prerest.length; let pos = 0; // Fast path: format is exactly "GT" if (format === 'GT') { for (let idx = 0; idx < samplesLen; idx++) { const start = pos; while (pos < prerestLen && prerest.charCodeAt(pos) !== TAB) { pos++; } callback(prerest, start, pos, idx); pos++; } return; } const colonCount = gtColumnIndex(format); if (colonCount === -1) { return; } // GT is first field but not only field if (colonCount === 0) { for (let idx = 0; idx < samplesLen; idx++) { const start = pos; while (pos < prerestLen && prerest.charCodeAt(pos) !== COLON && prerest.charCodeAt(pos) !== TAB) { pos++; } callback(prerest, start, pos, idx); while (pos < prerestLen && prerest.charCodeAt(pos) !== TAB) { pos++; } pos++; } return; } // GT is not first field - skip to its column (colonCount fields precede it) for (let idx = 0; idx < samplesLen; idx++) { const sampleStart = pos; let tabIdx = pos; while (tabIdx < prerestLen && prerest.charCodeAt(tabIdx) !== TAB) { tabIdx++; } let colons = 0; let fieldStart = sampleStart; for (let j = sampleStart; j <= tabIdx; j++) { if (j === tabIdx || prerest.charCodeAt(j) === COLON) { if (colons === colonCount) { callback(prerest, fieldStart, j, idx); break; } colons++; fieldStart = j + 1; } } pos = tabIdx + 1; } } //# sourceMappingURL=processGenotypes.js.map