UNPKG

@gmod/cram

Version:

read CRAM files with pure Javascript

137 lines 4.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.dataSeriesTypes = void 0; const index_ts_1 = require("../codecs/index.js"); // the hardcoded data type to be decoded for each core // data field const dataSeriesTypes = { BF: 'int', CF: 'int', RI: 'int', RL: 'int', AP: 'int', RG: 'int', MF: 'int', NS: 'int', NP: 'int', TS: 'int', NF: 'int', TC: 'byte', TN: 'int', FN: 'int', FC: 'byte', FP: 'int', BS: 'byte', IN: 'byteArray', SC: 'byteArray', DL: 'int', BA: 'byte', BB: 'byteArray', RS: 'int', PD: 'int', HC: 'int', MQ: 'int', RN: 'byteArray', QS: 'byte', QQ: 'byteArray', TL: 'int', // TM: 'ignore', // TV: 'ignore', }; exports.dataSeriesTypes = dataSeriesTypes; // For each reference base index 0..4 (A,C,G,T,N), the three other bases plus N // (or T for ref=N), in the order they're packed into the 2-bit substitution code const SUBSTITUTIONS = [ ['C', 'G', 'T', 'N'], ['A', 'G', 'T', 'N'], ['A', 'C', 'T', 'N'], ['A', 'C', 'G', 'N'], ['A', 'C', 'G', 'T'], ]; function parseSubstitutionMatrix(byteArray) { const matrix = new Array(5); for (let i = 0; i < 5; i++) { const row = new Array(4); const byte = byteArray[i]; const subs = SUBSTITUTIONS[i]; for (let j = 0; j < 4; j++) { row[(byte >> (6 - 2 * j)) & 3] = subs[j]; } matrix[i] = row; } return matrix; } class CramContainerCompressionScheme { readNamesIncluded; APdelta; referenceRequired; tagIdsDictionary; substitutionMatrix; dataSeriesCodecCache = {}; tagCodecCache = {}; tagEncoding = {}; dataSeriesEncoding; constructor(content) { // interpret some of the preservation map tags for convenient use // preservation-map defaults when a key is absent, per the CRAM spec // (matches htslib cram_decode.c): RN=false, AP=true, RR=true. this.readNamesIncluded = content.preservation.RN ?? false; this.APdelta = content.preservation.AP ?? true; this.referenceRequired = content.preservation.RR ?? true; this.tagIdsDictionary = content.preservation.TD; this.substitutionMatrix = parseSubstitutionMatrix(content.preservation.SM); this.dataSeriesEncoding = content.dataSeriesEncoding; this.tagEncoding = content.tagEncoding; } /** * @param {string} tagName three-character tag name * @private */ getCodecForTag(tagName) { if (!this.tagCodecCache[tagName]) { const encodingData = this.tagEncoding[tagName]; if (!encodingData) { throw new Error('Error, no tag encoding'); } // all tags are byte array data this.tagCodecCache[tagName] = (0, index_ts_1.instantiateCodec)(encodingData, 'byteArray'); } return this.tagCodecCache[tagName]; } /** * * @param {number} tagListId ID of the tag list to fetch from the tag dictionary * @private */ getTagNames(tagListId) { return this.tagIdsDictionary[tagListId]; } getCodecForDataSeries(dataSeriesName) { let r = this.dataSeriesCodecCache[dataSeriesName]; if (r === undefined) { const encodingData = this.dataSeriesEncoding[dataSeriesName]; if (encodingData) { r = (0, index_ts_1.instantiateCodec)(encodingData, dataSeriesTypes[dataSeriesName]); // TS can't unify the per-key cache value type with the generic // TDataSeries — store via an untyped slot. this.dataSeriesCodecCache[dataSeriesName] = r; } } return r; } // Used implicitly by snapshot tests to keep the codec caches (which contain // class instances and are noisy/non-stable) out of the serialized form. toJSON() { const data = {}; Object.keys(this).forEach(k => { if (k.endsWith('Cache')) { return; } data[k] = this[k]; }); return data; } } exports.default = CramContainerCompressionScheme; //# sourceMappingURL=compressionScheme.js.map