UNPKG

@gmod/cram

Version:

read CRAM files with pure Javascript

136 lines 4.45 kB
import { CramMalformedError } from "../../errors.js"; import { instantiateCodec } from "../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', }; function parseSubstitutionMatrix(byteArray) { const matrix = new Array(5); for (let i = 0; i < 5; i += 1) { matrix[i] = new Array(4); } matrix[0][(byteArray[0] >> 6) & 3] = 'C'; matrix[0][(byteArray[0] >> 4) & 3] = 'G'; matrix[0][(byteArray[0] >> 2) & 3] = 'T'; matrix[0][(byteArray[0] >> 0) & 3] = 'N'; matrix[1][(byteArray[1] >> 6) & 3] = 'A'; matrix[1][(byteArray[1] >> 4) & 3] = 'G'; matrix[1][(byteArray[1] >> 2) & 3] = 'T'; matrix[1][(byteArray[1] >> 0) & 3] = 'N'; matrix[2][(byteArray[2] >> 6) & 3] = 'A'; matrix[2][(byteArray[2] >> 4) & 3] = 'C'; matrix[2][(byteArray[2] >> 2) & 3] = 'T'; matrix[2][(byteArray[2] >> 0) & 3] = 'N'; matrix[3][(byteArray[3] >> 6) & 3] = 'A'; matrix[3][(byteArray[3] >> 4) & 3] = 'C'; matrix[3][(byteArray[3] >> 2) & 3] = 'G'; matrix[3][(byteArray[3] >> 0) & 3] = 'N'; matrix[4][(byteArray[4] >> 6) & 3] = 'A'; matrix[4][(byteArray[4] >> 4) & 3] = 'C'; matrix[4][(byteArray[4] >> 2) & 3] = 'G'; matrix[4][(byteArray[4] >> 0) & 3] = 'T'; return matrix; } export default class CramContainerCompressionScheme { constructor(content) { this.dataSeriesCodecCache = {}; this.tagCodecCache = {}; this.tagEncoding = {}; // interpret some of the preservation map tags for convenient use this.readNamesIncluded = content.preservation.RN; this.APdelta = content.preservation.AP; this.referenceRequired = !!content.preservation.RR; 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) { const test = this.tagCodecCache[tagName]; if (!test) { const encodingData = this.tagEncoding[tagName]; if (!encodingData) { throw new Error('Error, no tag encoding'); } const ret = instantiateCodec(encodingData, 'byteArray'); this.tagCodecCache[tagName] = ret; return ret; } else { return test; } } /** * * @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]; // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (encodingData) { const dataType = dataSeriesTypes[dataSeriesName]; // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (!dataType) { throw new CramMalformedError(`data series name ${dataSeriesName} not defined in file compression header`); } r = instantiateCodec(encodingData, dataType); // didn't find a way to make TS understand this this.dataSeriesCodecCache[dataSeriesName] = r; } } return r; } toJSON() { const data = {}; Object.keys(this).forEach(k => { if (k.endsWith('Cache')) { return; } data[k] = this[k]; }); return data; } } //# sourceMappingURL=compressionScheme.js.map